/**
 ******************************************************************************
 * @file    stm32f4xx_hal_rcc_ex.c
 * @author  MCD Application Team
 * @brief   Extension RCC HAL module driver.
 *          This file provides firmware functions to manage the following
 *          functionalities RCC extension peripheral:
 *           + Extended Peripheral Control functions
 *
 ******************************************************************************
 * @attention
 *
 * <h2><center>&copy; Copyright (c) 2017 STMicroelectronics.
 * All rights reserved.</center></h2>
 *
 * This software component is licensed by ST under BSD 3-Clause license,
 * the "License"; You may not use this file except in compliance with the
 * License. You may obtain a copy of the License at:
 *                        opensource.org/licenses/BSD-3-Clause
 *
 ******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_hal.h"

/** @addtogroup STM32F4xx_HAL_Driver
 * @{
 */

/** @defgroup RCCEx RCCEx
 * @brief RCCEx HAL module driver
 * @{
 */

#ifdef HAL_RCC_MODULE_ENABLED

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/** @addtogroup RCCEx_Private_Constants
 * @{
 */
/**
 * @}
 */
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/** @defgroup RCCEx_Exported_Functions RCCEx Exported Functions
 *  @{
 */

/** @defgroup RCCEx_Exported_Functions_Group1 Extended Peripheral Control functions
 *  @brief  Extended Peripheral Control functions
 *
@verbatim
 ===============================================================================
                ##### Extended Peripheral Control functions  #####
 ===============================================================================
    [..]
    This subsection provides a set of functions allowing to control the RCC Clocks
    frequencies.
    [..]
    (@) Important note: Care must be taken when HAL_RCCEx_PeriphCLKConfig() is used to
        select the RTC clock source; in this case the Backup domain will be reset in
        order to modify the RTC Clock source, as consequence RTC registers (including
        the backup registers) and RCC_BDCR register are set to their reset values.

@endverbatim
  * @{
  */

#    if defined(STM32F446xx)
/**
 * @brief  Initializes the RCC extended peripherals clocks according to the specified
 *         parameters in the RCC_PeriphCLKInitTypeDef.
 * @param  PeriphClkInit pointer to an RCC_PeriphCLKInitTypeDef structure that
 *         contains the configuration information for the Extended Peripherals
 *         clocks(I2S, SAI, LTDC RTC and TIM).
 *
 * @note   Care must be taken when HAL_RCCEx_PeriphCLKConfig() is used to select
 *         the RTC clock source; in this case the Backup domain will be reset in
 *         order to modify the RTC Clock source, as consequence RTC registers (including
 *         the backup registers) and RCC_BDCR register are set to their reset values.
 *
 * @retval HAL status
 */
HAL_StatusTypeDef HAL_RCCEx_PeriphCLKConfig(RCC_PeriphCLKInitTypeDef* PeriphClkInit)
{
    uint32_t tickstart = 0U;
    uint32_t tmpreg1 = 0U;
    uint32_t plli2sp = 0U;
    uint32_t plli2sq = 0U;
    uint32_t plli2sr = 0U;
    uint32_t pllsaip = 0U;
    uint32_t pllsaiq = 0U;
    uint32_t plli2sused = 0U;
    uint32_t pllsaiused = 0U;

    /* Check the peripheral clock selection parameters */
    assert_param(IS_RCC_PERIPHCLOCK(PeriphClkInit->PeriphClockSelection));

    /*------------------------ I2S APB1 configuration --------------------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_I2S_APB1) == (RCC_PERIPHCLK_I2S_APB1)) {
        /* Check the parameters */
        assert_param(IS_RCC_I2SAPB1CLKSOURCE(PeriphClkInit->I2sApb1ClockSelection));

        /* Configure I2S Clock source */
        __HAL_RCC_I2S_APB1_CONFIG(PeriphClkInit->I2sApb1ClockSelection);
        /* Enable the PLLI2S when it's used as clock source for I2S */
        if (PeriphClkInit->I2sApb1ClockSelection == RCC_I2SAPB1CLKSOURCE_PLLI2S) {
            plli2sused = 1U;
        }
    }
    /*--------------------------------------------------------------------------*/

    /*---------------------------- I2S APB2 configuration ----------------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_I2S_APB2) == (RCC_PERIPHCLK_I2S_APB2)) {
        /* Check the parameters */
        assert_param(IS_RCC_I2SAPB2CLKSOURCE(PeriphClkInit->I2sApb2ClockSelection));

        /* Configure I2S Clock source */
        __HAL_RCC_I2S_APB2_CONFIG(PeriphClkInit->I2sApb2ClockSelection);
        /* Enable the PLLI2S when it's used as clock source for I2S */
        if (PeriphClkInit->I2sApb2ClockSelection == RCC_I2SAPB2CLKSOURCE_PLLI2S) {
            plli2sused = 1U;
        }
    }
    /*--------------------------------------------------------------------------*/

    /*--------------------------- SAI1 configuration ---------------------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_SAI1) == (RCC_PERIPHCLK_SAI1)) {
        /* Check the parameters */
        assert_param(IS_RCC_SAI1CLKSOURCE(PeriphClkInit->Sai1ClockSelection));

        /* Configure SAI1 Clock source */
        __HAL_RCC_SAI1_CONFIG(PeriphClkInit->Sai1ClockSelection);
        /* Enable the PLLI2S when it's used as clock source for SAI */
        if (PeriphClkInit->Sai1ClockSelection == RCC_SAI1CLKSOURCE_PLLI2S) {
            plli2sused = 1U;
        }
        /* Enable the PLLSAI when it's used as clock source for SAI */
        if (PeriphClkInit->Sai1ClockSelection == RCC_SAI1CLKSOURCE_PLLSAI) {
            pllsaiused = 1U;
        }
    }
    /*--------------------------------------------------------------------------*/

    /*-------------------------- SAI2 configuration ----------------------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_SAI2) == (RCC_PERIPHCLK_SAI2)) {
        /* Check the parameters */
        assert_param(IS_RCC_SAI2CLKSOURCE(PeriphClkInit->Sai2ClockSelection));

        /* Configure SAI2 Clock source */
        __HAL_RCC_SAI2_CONFIG(PeriphClkInit->Sai2ClockSelection);

        /* Enable the PLLI2S when it's used as clock source for SAI */
        if (PeriphClkInit->Sai2ClockSelection == RCC_SAI2CLKSOURCE_PLLI2S) {
            plli2sused = 1U;
        }
        /* Enable the PLLSAI when it's used as clock source for SAI */
        if (PeriphClkInit->Sai2ClockSelection == RCC_SAI2CLKSOURCE_PLLSAI) {
            pllsaiused = 1U;
        }
    }
    /*--------------------------------------------------------------------------*/

    /*----------------------------- RTC configuration --------------------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_RTC) == (RCC_PERIPHCLK_RTC)) {
        /* Check for RTC Parameters used to output RTCCLK */
        assert_param(IS_RCC_RTCCLKSOURCE(PeriphClkInit->RTCClockSelection));

        /* Enable Power Clock*/
        __HAL_RCC_PWR_CLK_ENABLE();

        /* Enable write access to Backup domain */
        PWR->CR |= PWR_CR_DBP;

        /* Get tick */
        tickstart = HAL_GetTick();

        while ((PWR->CR & PWR_CR_DBP) == RESET) {
            if ((HAL_GetTick() - tickstart) > RCC_DBP_TIMEOUT_VALUE) {
                return HAL_TIMEOUT;
            }
        }
        /* Reset the Backup domain only if the RTC Clock source selection is modified from reset value */
        tmpreg1 = (RCC->BDCR & RCC_BDCR_RTCSEL);
        if ((tmpreg1 != 0x00000000U) && ((tmpreg1) != (PeriphClkInit->RTCClockSelection & RCC_BDCR_RTCSEL))) {
            /* Store the content of BDCR register before the reset of Backup Domain */
            tmpreg1 = (RCC->BDCR & ~(RCC_BDCR_RTCSEL));
            /* RTC Clock selection can be changed only if the Backup Domain is reset */
            __HAL_RCC_BACKUPRESET_FORCE();
            __HAL_RCC_BACKUPRESET_RELEASE();
            /* Restore the Content of BDCR register */
            RCC->BDCR = tmpreg1;

            /* Wait for LSE reactivation if LSE was enable prior to Backup Domain reset */
            if (HAL_IS_BIT_SET(RCC->BDCR, RCC_BDCR_LSEON)) {
                /* Get tick */
                tickstart = HAL_GetTick();

                /* Wait till LSE is ready */
                while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) == RESET) {
                    if ((HAL_GetTick() - tickstart) > RCC_LSE_TIMEOUT_VALUE) {
                        return HAL_TIMEOUT;
                    }
                }
            }
        }
        __HAL_RCC_RTC_CONFIG(PeriphClkInit->RTCClockSelection);
    }
    /*--------------------------------------------------------------------------*/

    /*---------------------------- TIM configuration ---------------------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_TIM) == (RCC_PERIPHCLK_TIM)) {
        /* Configure Timer Prescaler */
        __HAL_RCC_TIMCLKPRESCALER(PeriphClkInit->TIMPresSelection);
    }
    /*--------------------------------------------------------------------------*/

    /*---------------------------- FMPI2C1 Configuration -----------------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_FMPI2C1) == RCC_PERIPHCLK_FMPI2C1) {
        /* Check the parameters */
        assert_param(IS_RCC_FMPI2C1CLKSOURCE(PeriphClkInit->Fmpi2c1ClockSelection));

        /* Configure the FMPI2C1 clock source */
        __HAL_RCC_FMPI2C1_CONFIG(PeriphClkInit->Fmpi2c1ClockSelection);
    }
    /*--------------------------------------------------------------------------*/

    /*------------------------------ CEC Configuration -------------------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_CEC) == RCC_PERIPHCLK_CEC) {
        /* Check the parameters */
        assert_param(IS_RCC_CECCLKSOURCE(PeriphClkInit->CecClockSelection));

        /* Configure the CEC clock source */
        __HAL_RCC_CEC_CONFIG(PeriphClkInit->CecClockSelection);
    }
    /*--------------------------------------------------------------------------*/

    /*----------------------------- CLK48 Configuration ------------------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_CLK48) == RCC_PERIPHCLK_CLK48) {
        /* Check the parameters */
        assert_param(IS_RCC_CLK48CLKSOURCE(PeriphClkInit->Clk48ClockSelection));

        /* Configure the CLK48 clock source */
        __HAL_RCC_CLK48_CONFIG(PeriphClkInit->Clk48ClockSelection);

        /* Enable the PLLSAI when it's used as clock source for CLK48 */
        if (PeriphClkInit->Clk48ClockSelection == RCC_CLK48CLKSOURCE_PLLSAIP) {
            pllsaiused = 1U;
        }
    }
    /*--------------------------------------------------------------------------*/

    /*----------------------------- SDIO Configuration -------------------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_SDIO) == RCC_PERIPHCLK_SDIO) {
        /* Check the parameters */
        assert_param(IS_RCC_SDIOCLKSOURCE(PeriphClkInit->SdioClockSelection));

        /* Configure the SDIO clock source */
        __HAL_RCC_SDIO_CONFIG(PeriphClkInit->SdioClockSelection);
    }
    /*--------------------------------------------------------------------------*/

    /*------------------------------ SPDIFRX Configuration ---------------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_SPDIFRX) == RCC_PERIPHCLK_SPDIFRX) {
        /* Check the parameters */
        assert_param(IS_RCC_SPDIFRXCLKSOURCE(PeriphClkInit->SpdifClockSelection));

        /* Configure the SPDIFRX clock source */
        __HAL_RCC_SPDIFRX_CONFIG(PeriphClkInit->SpdifClockSelection);
        /* Enable the PLLI2S when it's used as clock source for SPDIFRX */
        if (PeriphClkInit->SpdifClockSelection == RCC_SPDIFRXCLKSOURCE_PLLI2SP) {
            plli2sused = 1U;
        }
    }
    /*--------------------------------------------------------------------------*/

    /*---------------------------- PLLI2S Configuration ------------------------*/
    /* PLLI2S is configured when a peripheral will use it as source clock : SAI1, SAI2, I2S on APB1,
       I2S on APB2 or SPDIFRX */
    if ((plli2sused == 1U) || (PeriphClkInit->PeriphClockSelection == RCC_PERIPHCLK_PLLI2S)) {
        /* Disable the PLLI2S */
        __HAL_RCC_PLLI2S_DISABLE();
        /* Get tick */
        tickstart = HAL_GetTick();
        /* Wait till PLLI2S is disabled */
        while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLI2SRDY) != RESET) {
            if ((HAL_GetTick() - tickstart) > PLLI2S_TIMEOUT_VALUE) {
                /* return in case of Timeout detected */
                return HAL_TIMEOUT;
            }
        }

        /* check for common PLLI2S Parameters */
        assert_param(IS_RCC_PLLI2SM_VALUE(PeriphClkInit->PLLI2S.PLLI2SM));
        assert_param(IS_RCC_PLLI2SN_VALUE(PeriphClkInit->PLLI2S.PLLI2SN));

        /*------ In Case of PLLI2S is selected as source clock for I2S -----------*/
        if (((((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_I2S_APB1) == RCC_PERIPHCLK_I2S_APB1)
             && (PeriphClkInit->I2sApb1ClockSelection == RCC_I2SAPB1CLKSOURCE_PLLI2S))
            || ((((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_I2S_APB2) == RCC_PERIPHCLK_I2S_APB2)
                && (PeriphClkInit->I2sApb2ClockSelection == RCC_I2SAPB2CLKSOURCE_PLLI2S))) {
            /* check for Parameters */
            assert_param(IS_RCC_PLLI2SR_VALUE(PeriphClkInit->PLLI2S.PLLI2SR));

            /* Read PLLI2SP/PLLI2SQ value from PLLI2SCFGR register (this value is not needed for I2S configuration) */
            plli2sp = ((((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SP) >> RCC_PLLI2SCFGR_PLLI2SP_Pos) + 1U) << 1U);
            plli2sq = ((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SQ) >> RCC_PLLI2SCFGR_PLLI2SQ_Pos);
            /* Configure the PLLI2S division factors */
            /* PLLI2S_VCO = f(VCO clock) = f(PLLI2S clock input) * (PLLI2SN/PLLI2SM) */
            /* I2SCLK = f(PLLI2S clock output) = f(VCO clock) / PLLI2SR */
            __HAL_RCC_PLLI2S_CONFIG(PeriphClkInit->PLLI2S.PLLI2SM,
                                    PeriphClkInit->PLLI2S.PLLI2SN,
                                    plli2sp,
                                    plli2sq,
                                    PeriphClkInit->PLLI2S.PLLI2SR);
        }

        /*------- In Case of PLLI2S is selected as source clock for SAI ----------*/
        if (((((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_SAI1) == RCC_PERIPHCLK_SAI1)
             && (PeriphClkInit->Sai1ClockSelection == RCC_SAI1CLKSOURCE_PLLI2S))
            || ((((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_SAI2) == RCC_PERIPHCLK_SAI2)
                && (PeriphClkInit->Sai2ClockSelection == RCC_SAI2CLKSOURCE_PLLI2S))) {
            /* Check for PLLI2S Parameters */
            assert_param(IS_RCC_PLLI2SQ_VALUE(PeriphClkInit->PLLI2S.PLLI2SQ));
            /* Check for PLLI2S/DIVQ parameters */
            assert_param(IS_RCC_PLLI2S_DIVQ_VALUE(PeriphClkInit->PLLI2SDivQ));

            /* Read PLLI2SP/PLLI2SR value from PLLI2SCFGR register (this value is not needed for SAI configuration) */
            plli2sp = ((((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SP) >> RCC_PLLI2SCFGR_PLLI2SP_Pos) + 1U) << 1U);
            plli2sr = ((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SR) >> RCC_PLLI2SCFGR_PLLI2SR_Pos);
            /* Configure the PLLI2S division factors */
            /* PLLI2S_VCO Input  = PLL_SOURCE/PLLI2SM */
            /* PLLI2S_VCO Output = PLLI2S_VCO Input * PLLI2SN */
            /* SAI_CLK(first level) = PLLI2S_VCO Output/PLLI2SQ */
            __HAL_RCC_PLLI2S_CONFIG(PeriphClkInit->PLLI2S.PLLI2SM,
                                    PeriphClkInit->PLLI2S.PLLI2SN,
                                    plli2sp,
                                    PeriphClkInit->PLLI2S.PLLI2SQ,
                                    plli2sr);

            /* SAI_CLK_x = SAI_CLK(first level)/PLLI2SDIVQ */
            __HAL_RCC_PLLI2S_PLLSAICLKDIVQ_CONFIG(PeriphClkInit->PLLI2SDivQ);
        }

        /*------ In Case of PLLI2S is selected as source clock for SPDIFRX -------*/
        if ((((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_SPDIFRX) == RCC_PERIPHCLK_SPDIFRX)
            && (PeriphClkInit->SpdifClockSelection == RCC_SPDIFRXCLKSOURCE_PLLI2SP)) {
            /* check for Parameters */
            assert_param(IS_RCC_PLLI2SP_VALUE(PeriphClkInit->PLLI2S.PLLI2SP));
            /* Read PLLI2SR value from PLLI2SCFGR register (this value is not need for SAI configuration) */
            plli2sq = ((((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SP) >> RCC_PLLI2SCFGR_PLLI2SP_Pos) + 1U) << 1U);
            plli2sr = ((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SR) >> RCC_PLLI2SCFGR_PLLI2SR_Pos);
            /* Configure the PLLI2S division factors */
            /* PLLI2S_VCO = f(VCO clock) = f(PLLI2S clock input) * (PLLI2SN/PLLI2SM) */
            /* SPDIFRXCLK = f(PLLI2S clock output) = f(VCO clock) / PLLI2SP */
            __HAL_RCC_PLLI2S_CONFIG(PeriphClkInit->PLLI2S.PLLI2SM,
                                    PeriphClkInit->PLLI2S.PLLI2SN,
                                    PeriphClkInit->PLLI2S.PLLI2SP,
                                    plli2sq,
                                    plli2sr);
        }

        /*----------------- In Case of PLLI2S is just selected  -----------------*/
        if ((PeriphClkInit->PeriphClockSelection & RCC_PERIPHCLK_PLLI2S) == RCC_PERIPHCLK_PLLI2S) {
            /* Check for Parameters */
            assert_param(IS_RCC_PLLI2SP_VALUE(PeriphClkInit->PLLI2S.PLLI2SP));
            assert_param(IS_RCC_PLLI2SR_VALUE(PeriphClkInit->PLLI2S.PLLI2SR));
            assert_param(IS_RCC_PLLI2SQ_VALUE(PeriphClkInit->PLLI2S.PLLI2SQ));

            /* Configure the PLLI2S division factors */
            /* PLLI2S_VCO = f(VCO clock) = f(PLLI2S clock input) * (PLLI2SN/PLLI2SM) */
            __HAL_RCC_PLLI2S_CONFIG(PeriphClkInit->PLLI2S.PLLI2SM,
                                    PeriphClkInit->PLLI2S.PLLI2SN,
                                    PeriphClkInit->PLLI2S.PLLI2SP,
                                    PeriphClkInit->PLLI2S.PLLI2SQ,
                                    PeriphClkInit->PLLI2S.PLLI2SR);
        }

        /* Enable the PLLI2S */
        __HAL_RCC_PLLI2S_ENABLE();
        /* Get tick */
        tickstart = HAL_GetTick();
        /* Wait till PLLI2S is ready */
        while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLI2SRDY) == RESET) {
            if ((HAL_GetTick() - tickstart) > PLLI2S_TIMEOUT_VALUE) {
                /* return in case of Timeout detected */
                return HAL_TIMEOUT;
            }
        }
    }
    /*--------------------------------------------------------------------------*/

    /*----------------------------- PLLSAI Configuration -----------------------*/
    /* PLLSAI is configured when a peripheral will use it as source clock : SAI1, SAI2, CLK48 or SDIO */
    if (pllsaiused == 1U) {
        /* Disable PLLSAI Clock */
        __HAL_RCC_PLLSAI_DISABLE();
        /* Get tick */
        tickstart = HAL_GetTick();
        /* Wait till PLLSAI is disabled */
        while (__HAL_RCC_PLLSAI_GET_FLAG() != RESET) {
            if ((HAL_GetTick() - tickstart) > PLLSAI_TIMEOUT_VALUE) {
                /* return in case of Timeout detected */
                return HAL_TIMEOUT;
            }
        }

        /* Check the PLLSAI division factors */
        assert_param(IS_RCC_PLLSAIM_VALUE(PeriphClkInit->PLLSAI.PLLSAIM));
        assert_param(IS_RCC_PLLSAIN_VALUE(PeriphClkInit->PLLSAI.PLLSAIN));

        /*------ In Case of PLLSAI is selected as source clock for SAI -----------*/
        if (((((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_SAI1) == RCC_PERIPHCLK_SAI1)
             && (PeriphClkInit->Sai1ClockSelection == RCC_SAI1CLKSOURCE_PLLSAI))
            || ((((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_SAI2) == RCC_PERIPHCLK_SAI2)
                && (PeriphClkInit->Sai2ClockSelection == RCC_SAI2CLKSOURCE_PLLSAI))) {
            /* check for PLLSAIQ Parameter */
            assert_param(IS_RCC_PLLSAIQ_VALUE(PeriphClkInit->PLLSAI.PLLSAIQ));
            /* check for PLLSAI/DIVQ Parameter */
            assert_param(IS_RCC_PLLSAI_DIVQ_VALUE(PeriphClkInit->PLLSAIDivQ));

            /* Read PLLSAIP value from PLLSAICFGR register (this value is not needed for SAI configuration) */
            pllsaip = ((((RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIP) >> RCC_PLLSAICFGR_PLLSAIP_Pos) + 1U) << 1U);
            /* PLLSAI_VCO Input  = PLL_SOURCE/PLLM */
            /* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAIN */
            /* SAI_CLK(first level) = PLLSAI_VCO Output/PLLSAIQ */
            __HAL_RCC_PLLSAI_CONFIG(PeriphClkInit->PLLSAI.PLLSAIM,
                                    PeriphClkInit->PLLSAI.PLLSAIN,
                                    pllsaip,
                                    PeriphClkInit->PLLSAI.PLLSAIQ,
                                    0U);

            /* SAI_CLK_x = SAI_CLK(first level)/PLLSAIDIVQ */
            __HAL_RCC_PLLSAI_PLLSAICLKDIVQ_CONFIG(PeriphClkInit->PLLSAIDivQ);
        }

        /*------ In Case of PLLSAI is selected as source clock for CLK48 ---------*/
        /* In Case of PLLI2S is selected as source clock for CLK48 */
        if ((((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_CLK48) == RCC_PERIPHCLK_CLK48)
            && (PeriphClkInit->Clk48ClockSelection == RCC_CLK48CLKSOURCE_PLLSAIP)) {
            /* check for Parameters */
            assert_param(IS_RCC_PLLSAIP_VALUE(PeriphClkInit->PLLSAI.PLLSAIP));
            /* Read PLLSAIQ value from PLLI2SCFGR register (this value is not need for SAI configuration) */
            pllsaiq = ((RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIQ) >> RCC_PLLSAICFGR_PLLSAIQ_Pos);
            /* Configure the PLLSAI division factors */
            /* PLLSAI_VCO = f(VCO clock) = f(PLLSAI clock input) * (PLLI2SN/PLLSAIM) */
            /* 48CLK = f(PLLSAI clock output) = f(VCO clock) / PLLSAIP */
            __HAL_RCC_PLLSAI_CONFIG(PeriphClkInit->PLLSAI.PLLSAIM,
                                    PeriphClkInit->PLLSAI.PLLSAIN,
                                    PeriphClkInit->PLLSAI.PLLSAIP,
                                    pllsaiq,
                                    0U);
        }

        /* Enable PLLSAI Clock */
        __HAL_RCC_PLLSAI_ENABLE();
        /* Get tick */
        tickstart = HAL_GetTick();
        /* Wait till PLLSAI is ready */
        while (__HAL_RCC_PLLSAI_GET_FLAG() == RESET) {
            if ((HAL_GetTick() - tickstart) > PLLSAI_TIMEOUT_VALUE) {
                /* return in case of Timeout detected */
                return HAL_TIMEOUT;
            }
        }
    }
    return HAL_OK;
}

/**
 * @brief  Get the RCC_PeriphCLKInitTypeDef according to the internal
 *         RCC configuration registers.
 * @param  PeriphClkInit pointer to an RCC_PeriphCLKInitTypeDef structure that
 *         will be configured.
 * @retval None
 */
void HAL_RCCEx_GetPeriphCLKConfig(RCC_PeriphCLKInitTypeDef* PeriphClkInit)
{
    uint32_t tempreg;

    /* Set all possible values for the extended clock type parameter------------*/
    PeriphClkInit->PeriphClockSelection = RCC_PERIPHCLK_I2S_APB1 | RCC_PERIPHCLK_I2S_APB2 | RCC_PERIPHCLK_SAI1
                                          | RCC_PERIPHCLK_SAI2 | RCC_PERIPHCLK_TIM | RCC_PERIPHCLK_RTC
                                          | RCC_PERIPHCLK_CEC | RCC_PERIPHCLK_FMPI2C1 | RCC_PERIPHCLK_CLK48
                                          | RCC_PERIPHCLK_SDIO | RCC_PERIPHCLK_SPDIFRX;

    /* Get the PLLI2S Clock configuration --------------------------------------*/
    PeriphClkInit->PLLI2S.PLLI2SM =
        (uint32_t)((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SM) >> RCC_PLLI2SCFGR_PLLI2SM_Pos);
    PeriphClkInit->PLLI2S.PLLI2SN =
        (uint32_t)((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SN) >> RCC_PLLI2SCFGR_PLLI2SN_Pos);
    PeriphClkInit->PLLI2S.PLLI2SP =
        (uint32_t)((((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SP) >> RCC_PLLI2SCFGR_PLLI2SP_Pos) + 1U) << 1U);
    PeriphClkInit->PLLI2S.PLLI2SQ =
        (uint32_t)((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SQ) >> RCC_PLLI2SCFGR_PLLI2SQ_Pos);
    PeriphClkInit->PLLI2S.PLLI2SR =
        (uint32_t)((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SR) >> RCC_PLLI2SCFGR_PLLI2SR_Pos);
    /* Get the PLLSAI Clock configuration --------------------------------------*/
    PeriphClkInit->PLLSAI.PLLSAIM =
        (uint32_t)((RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIM) >> RCC_PLLSAICFGR_PLLSAIM_Pos);
    PeriphClkInit->PLLSAI.PLLSAIN =
        (uint32_t)((RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIN) >> RCC_PLLSAICFGR_PLLSAIN_Pos);
    PeriphClkInit->PLLSAI.PLLSAIP =
        (uint32_t)((((RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIP) >> RCC_PLLSAICFGR_PLLSAIP_Pos) + 1U) << 1U);
    PeriphClkInit->PLLSAI.PLLSAIQ =
        (uint32_t)((RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIQ) >> RCC_PLLSAICFGR_PLLSAIQ_Pos);
    /* Get the PLLSAI/PLLI2S division factors ----------------------------------*/
    PeriphClkInit->PLLI2SDivQ = (uint32_t)((RCC->DCKCFGR & RCC_DCKCFGR_PLLI2SDIVQ) >> RCC_DCKCFGR_PLLI2SDIVQ_Pos);
    PeriphClkInit->PLLSAIDivQ = (uint32_t)((RCC->DCKCFGR & RCC_DCKCFGR_PLLSAIDIVQ) >> RCC_DCKCFGR_PLLSAIDIVQ_Pos);

    /* Get the SAI1 clock configuration ----------------------------------------*/
    PeriphClkInit->Sai1ClockSelection = __HAL_RCC_GET_SAI1_SOURCE();

    /* Get the SAI2 clock configuration ----------------------------------------*/
    PeriphClkInit->Sai2ClockSelection = __HAL_RCC_GET_SAI2_SOURCE();

    /* Get the I2S APB1 clock configuration ------------------------------------*/
    PeriphClkInit->I2sApb1ClockSelection = __HAL_RCC_GET_I2S_APB1_SOURCE();

    /* Get the I2S APB2 clock configuration ------------------------------------*/
    PeriphClkInit->I2sApb2ClockSelection = __HAL_RCC_GET_I2S_APB2_SOURCE();

    /* Get the RTC Clock configuration -----------------------------------------*/
    tempreg = (RCC->CFGR & RCC_CFGR_RTCPRE);
    PeriphClkInit->RTCClockSelection = (uint32_t)((tempreg) | (RCC->BDCR & RCC_BDCR_RTCSEL));

    /* Get the CEC clock configuration -----------------------------------------*/
    PeriphClkInit->CecClockSelection = __HAL_RCC_GET_CEC_SOURCE();

    /* Get the FMPI2C1 clock configuration -------------------------------------*/
    PeriphClkInit->Fmpi2c1ClockSelection = __HAL_RCC_GET_FMPI2C1_SOURCE();

    /* Get the CLK48 clock configuration ----------------------------------------*/
    PeriphClkInit->Clk48ClockSelection = __HAL_RCC_GET_CLK48_SOURCE();

    /* Get the SDIO clock configuration ----------------------------------------*/
    PeriphClkInit->SdioClockSelection = __HAL_RCC_GET_SDIO_SOURCE();

    /* Get the SPDIFRX clock configuration -------------------------------------*/
    PeriphClkInit->SpdifClockSelection = __HAL_RCC_GET_SPDIFRX_SOURCE();

    /* Get the TIM Prescaler configuration -------------------------------------*/
    if ((RCC->DCKCFGR & RCC_DCKCFGR_TIMPRE) == RESET) {
        PeriphClkInit->TIMPresSelection = RCC_TIMPRES_DESACTIVATED;
    }
    else {
        PeriphClkInit->TIMPresSelection = RCC_TIMPRES_ACTIVATED;
    }
}

/**
 * @brief  Return the peripheral clock frequency for a given peripheral(SAI..)
 * @note   Return 0 if peripheral clock identifier not managed by this API
 * @param  PeriphClk Peripheral clock identifier
 *         This parameter can be one of the following values:
 *            @arg RCC_PERIPHCLK_SAI1: SAI1 peripheral clock
 *            @arg RCC_PERIPHCLK_SAI2: SAI2 peripheral clock
 *            @arg RCC_PERIPHCLK_I2S_APB1: I2S APB1 peripheral clock
 *            @arg RCC_PERIPHCLK_I2S_APB2: I2S APB2 peripheral clock
 * @retval Frequency in KHz
 */
uint32_t HAL_RCCEx_GetPeriphCLKFreq(uint32_t PeriphClk)
{
    uint32_t tmpreg1 = 0U;
    /* This variable used to store the SAI clock frequency (value in Hz) */
    uint32_t frequency = 0U;
    /* This variable used to store the VCO Input (value in Hz) */
    uint32_t vcoinput = 0U;
    /* This variable used to store the SAI clock source */
    uint32_t saiclocksource = 0U;
    uint32_t srcclk = 0U;
    /* This variable used to store the VCO Output (value in Hz) */
    uint32_t vcooutput = 0U;
    switch (PeriphClk) {
        case RCC_PERIPHCLK_SAI1:
        case RCC_PERIPHCLK_SAI2: {
            saiclocksource = RCC->DCKCFGR;
            saiclocksource &= (RCC_DCKCFGR_SAI1SRC | RCC_DCKCFGR_SAI2SRC);
            switch (saiclocksource) {
                case 0U: /* PLLSAI is the clock source for SAI*/
                {
                    /* Configure the PLLSAI division factor */
                    /* PLLSAI_VCO Input  = PLL_SOURCE/PLLSAIM */
                    if ((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLSOURCE_HSI) {
                        /* In Case the PLL Source is HSI (Internal Clock) */
                        vcoinput = (HSI_VALUE / (uint32_t)(RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIM));
                    }
                    else {
                        /* In Case the PLL Source is HSE (External Clock) */
                        vcoinput = ((HSE_VALUE / (uint32_t)(RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIM)));
                    }
                    /* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAIN */
                    /* SAI_CLK(first level) = PLLSAI_VCO Output/PLLSAIQ */
                    tmpreg1 = (RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIQ) >> 24U;
                    frequency = (vcoinput * ((RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIN) >> 6U)) / (tmpreg1);

                    /* SAI_CLK_x = SAI_CLK(first level)/PLLSAIDIVQ */
                    tmpreg1 = (((RCC->DCKCFGR & RCC_DCKCFGR_PLLSAIDIVQ) >> 8U) + 1U);
                    frequency = frequency / (tmpreg1);
                    break;
                }
                case RCC_DCKCFGR_SAI1SRC_0: /* PLLI2S is the clock source for SAI*/
                case RCC_DCKCFGR_SAI2SRC_0: /* PLLI2S is the clock source for SAI*/
                {
                    /* Configure the PLLI2S division factor */
                    /* PLLI2S_VCO Input  = PLL_SOURCE/PLLI2SM */
                    if ((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLSOURCE_HSI) {
                        /* In Case the PLL Source is HSI (Internal Clock) */
                        vcoinput = (HSI_VALUE / (uint32_t)(RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SM));
                    }
                    else {
                        /* In Case the PLL Source is HSE (External Clock) */
                        vcoinput = ((HSE_VALUE / (uint32_t)(RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SM)));
                    }

                    /* PLLI2S_VCO Output = PLLI2S_VCO Input * PLLI2SN */
                    /* SAI_CLK(first level) = PLLI2S_VCO Output/PLLI2SQ */
                    tmpreg1 = (RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SQ) >> 24U;
                    frequency = (vcoinput * ((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SN) >> 6U)) / (tmpreg1);

                    /* SAI_CLK_x = SAI_CLK(first level)/PLLI2SDIVQ */
                    tmpreg1 = ((RCC->DCKCFGR & RCC_DCKCFGR_PLLI2SDIVQ) + 1U);
                    frequency = frequency / (tmpreg1);
                    break;
                }
                case RCC_DCKCFGR_SAI1SRC_1: /* PLLR is the clock source for SAI*/
                case RCC_DCKCFGR_SAI2SRC_1: /* PLLR is the clock source for SAI*/
                {
                    /* Configure the PLLI2S division factor */
                    /* PLL_VCO Input  = PLL_SOURCE/PLLM */
                    if ((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLSOURCE_HSI) {
                        /* In Case the PLL Source is HSI (Internal Clock) */
                        vcoinput = (HSI_VALUE / (uint32_t)(RCC->PLLCFGR & RCC_PLLCFGR_PLLM));
                    }
                    else {
                        /* In Case the PLL Source is HSE (External Clock) */
                        vcoinput = ((HSE_VALUE / (uint32_t)(RCC->PLLCFGR & RCC_PLLCFGR_PLLM)));
                    }

                    /* PLL_VCO Output = PLL_VCO Input * PLLN */
                    /* SAI_CLK_x = PLL_VCO Output/PLLR */
                    tmpreg1 = (RCC->PLLCFGR & RCC_PLLCFGR_PLLR) >> 28U;
                    frequency = (vcoinput * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6U)) / (tmpreg1);
                    break;
                }
                case RCC_DCKCFGR_SAI1SRC: /* External clock is the clock source for SAI*/
                {
                    frequency = EXTERNAL_CLOCK_VALUE;
                    break;
                }
                case RCC_DCKCFGR_SAI2SRC: /* PLLSRC(HSE or HSI) is the clock source for SAI*/
                {
                    if ((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLSOURCE_HSI) {
                        /* In Case the PLL Source is HSI (Internal Clock) */
                        frequency = (uint32_t)(HSI_VALUE);
                    }
                    else {
                        /* In Case the PLL Source is HSE (External Clock) */
                        frequency = (uint32_t)(HSE_VALUE);
                    }
                    break;
                }
                default: {
                    break;
                }
            }
            break;
        }
        case RCC_PERIPHCLK_I2S_APB1: {
            /* Get the current I2S source */
            srcclk = __HAL_RCC_GET_I2S_APB1_SOURCE();
            switch (srcclk) {
                /* Check if I2S clock selection is External clock mapped on the I2S_CKIN pin used as I2S clock */
                case RCC_I2SAPB1CLKSOURCE_EXT: {
                    /* Set the I2S clock to the external clock  value */
                    frequency = EXTERNAL_CLOCK_VALUE;
                    break;
                }
                /* Check if I2S clock selection is PLLI2S VCO output clock divided by PLLI2SR used as I2S clock */
                case RCC_I2SAPB1CLKSOURCE_PLLI2S: {
                    /* Configure the PLLI2S division factor */
                    /* PLLI2S_VCO Input  = PLL_SOURCE/PLLI2SM */
                    if ((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLSOURCE_HSE) {
                        /* Get the I2S source clock value */
                        vcoinput = (uint32_t)(HSE_VALUE / (uint32_t)(RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SM));
                    }
                    else {
                        /* Get the I2S source clock value */
                        vcoinput = (uint32_t)(HSI_VALUE / (uint32_t)(RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SM));
                    }

                    /* PLLI2S_VCO Output = PLLI2S_VCO Input * PLLI2SN */
                    vcooutput = (uint32_t)(
                        vcoinput
                        * (((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SN) >> 6U) & (RCC_PLLI2SCFGR_PLLI2SN >> 6U)));
                    /* I2S_CLK = PLLI2S_VCO Output/PLLI2SR */
                    frequency = (uint32_t)(
                        vcooutput
                        / (((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SR) >> 28U) & (RCC_PLLI2SCFGR_PLLI2SR >> 28U)));
                    break;
                }
                /* Check if I2S clock selection is PLL VCO Output divided by PLLR used as I2S clock */
                case RCC_I2SAPB1CLKSOURCE_PLLR: {
                    /* Configure the PLL division factor R */
                    /* PLL_VCO Input  = PLL_SOURCE/PLLM */
                    if ((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLSOURCE_HSE) {
                        /* Get the I2S source clock value */
                        vcoinput = (uint32_t)(HSE_VALUE / (uint32_t)(RCC->PLLCFGR & RCC_PLLCFGR_PLLM));
                    }
                    else {
                        /* Get the I2S source clock value */
                        vcoinput = (uint32_t)(HSI_VALUE / (uint32_t)(RCC->PLLCFGR & RCC_PLLCFGR_PLLM));
                    }

                    /* PLL_VCO Output = PLL_VCO Input * PLLN */
                    vcooutput =
                        (uint32_t)(vcoinput * (((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6U) & (RCC_PLLCFGR_PLLN >> 6U)));
                    /* I2S_CLK = PLL_VCO Output/PLLR */
                    frequency = (uint32_t)(vcooutput
                                           / (((RCC->PLLCFGR & RCC_PLLCFGR_PLLR) >> 28U) & (RCC_PLLCFGR_PLLR >> 28U)));
                    break;
                }
                /* Check if I2S clock selection is HSI or HSE depending from PLL source Clock */
                case RCC_I2SAPB1CLKSOURCE_PLLSRC: {
                    if ((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLSOURCE_HSE) {
                        frequency = HSE_VALUE;
                    }
                    else {
                        frequency = HSI_VALUE;
                    }
                    break;
                }
                    /* Clock not enabled for I2S*/
                default: {
                    frequency = 0U;
                    break;
                }
            }
            break;
        }
        case RCC_PERIPHCLK_I2S_APB2: {
            /* Get the current I2S source */
            srcclk = __HAL_RCC_GET_I2S_APB2_SOURCE();
            switch (srcclk) {
                    /* Check if I2S clock selection is External clock mapped on the I2S_CKIN pin used as I2S clock */
                case RCC_I2SAPB2CLKSOURCE_EXT: {
                    /* Set the I2S clock to the external clock  value */
                    frequency = EXTERNAL_CLOCK_VALUE;
                    break;
                }
                    /* Check if I2S clock selection is PLLI2S VCO output clock divided by PLLI2SR used as I2S clock */
                case RCC_I2SAPB2CLKSOURCE_PLLI2S: {
                    /* Configure the PLLI2S division factor */
                    /* PLLI2S_VCO Input  = PLL_SOURCE/PLLI2SM */
                    if ((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLSOURCE_HSE) {
                        /* Get the I2S source clock value */
                        vcoinput = (uint32_t)(HSE_VALUE / (uint32_t)(RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SM));
                    }
                    else {
                        /* Get the I2S source clock value */
                        vcoinput = (uint32_t)(HSI_VALUE / (uint32_t)(RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SM));
                    }

                    /* PLLI2S_VCO Output = PLLI2S_VCO Input * PLLI2SN */
                    vcooutput = (uint32_t)(
                        vcoinput
                        * (((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SN) >> 6U) & (RCC_PLLI2SCFGR_PLLI2SN >> 6U)));
                    /* I2S_CLK = PLLI2S_VCO Output/PLLI2SR */
                    frequency = (uint32_t)(
                        vcooutput
                        / (((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SR) >> 28U) & (RCC_PLLI2SCFGR_PLLI2SR >> 28U)));
                    break;
                }
                    /* Check if I2S clock selection is PLL VCO Output divided by PLLR used as I2S clock */
                case RCC_I2SAPB2CLKSOURCE_PLLR: {
                    /* Configure the PLL division factor R */
                    /* PLL_VCO Input  = PLL_SOURCE/PLLM */
                    if ((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLSOURCE_HSE) {
                        /* Get the I2S source clock value */
                        vcoinput = (uint32_t)(HSE_VALUE / (uint32_t)(RCC->PLLCFGR & RCC_PLLCFGR_PLLM));
                    }
                    else {
                        /* Get the I2S source clock value */
                        vcoinput = (uint32_t)(HSI_VALUE / (uint32_t)(RCC->PLLCFGR & RCC_PLLCFGR_PLLM));
                    }

                    /* PLL_VCO Output = PLL_VCO Input * PLLN */
                    vcooutput =
                        (uint32_t)(vcoinput * (((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6U) & (RCC_PLLCFGR_PLLN >> 6U)));
                    /* I2S_CLK = PLL_VCO Output/PLLR */
                    frequency = (uint32_t)(vcooutput
                                           / (((RCC->PLLCFGR & RCC_PLLCFGR_PLLR) >> 28U) & (RCC_PLLCFGR_PLLR >> 28U)));
                    break;
                }
                    /* Check if I2S clock selection is HSI or HSE depending from PLL source Clock */
                case RCC_I2SAPB2CLKSOURCE_PLLSRC: {
                    if ((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLSOURCE_HSE) {
                        frequency = HSE_VALUE;
                    }
                    else {
                        frequency = HSI_VALUE;
                    }
                    break;
                }
                    /* Clock not enabled for I2S*/
                default: {
                    frequency = 0U;
                    break;
                }
            }
            break;
        }
    }
    return frequency;
}
#    endif /* STM32F446xx */

#    if defined(STM32F469xx) || defined(STM32F479xx)
/**
 * @brief  Initializes the RCC extended peripherals clocks according to the specified
 *         parameters in the RCC_PeriphCLKInitTypeDef.
 * @param  PeriphClkInit pointer to an RCC_PeriphCLKInitTypeDef structure that
 *         contains the configuration information for the Extended Peripherals
 *         clocks(I2S, SAI, LTDC, RTC and TIM).
 *
 * @note   Care must be taken when HAL_RCCEx_PeriphCLKConfig() is used to select
 *         the RTC clock source; in this case the Backup domain will be reset in
 *         order to modify the RTC Clock source, as consequence RTC registers (including
 *         the backup registers) and RCC_BDCR register are set to their reset values.
 *
 * @retval HAL status
 */
HAL_StatusTypeDef HAL_RCCEx_PeriphCLKConfig(RCC_PeriphCLKInitTypeDef* PeriphClkInit)
{
    uint32_t tickstart = 0U;
    uint32_t tmpreg1 = 0U;
    uint32_t pllsaip = 0U;
    uint32_t pllsaiq = 0U;
    uint32_t pllsair = 0U;

    /* Check the parameters */
    assert_param(IS_RCC_PERIPHCLOCK(PeriphClkInit->PeriphClockSelection));

    /*--------------------------- CLK48 Configuration --------------------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_CLK48) == RCC_PERIPHCLK_CLK48) {
        /* Check the parameters */
        assert_param(IS_RCC_CLK48CLKSOURCE(PeriphClkInit->Clk48ClockSelection));

        /* Configure the CLK48 clock source */
        __HAL_RCC_CLK48_CONFIG(PeriphClkInit->Clk48ClockSelection);
    }
    /*--------------------------------------------------------------------------*/

    /*------------------------------ SDIO Configuration ------------------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_SDIO) == RCC_PERIPHCLK_SDIO) {
        /* Check the parameters */
        assert_param(IS_RCC_SDIOCLKSOURCE(PeriphClkInit->SdioClockSelection));

        /* Configure the SDIO clock source */
        __HAL_RCC_SDIO_CONFIG(PeriphClkInit->SdioClockSelection);
    }
    /*--------------------------------------------------------------------------*/

    /*----------------------- SAI/I2S Configuration (PLLI2S) -------------------*/
    /*------------------- Common configuration SAI/I2S -------------------------*/
    /* In Case of SAI or I2S Clock Configuration through PLLI2S, PLLI2SN division
       factor is common parameters for both peripherals */
    if ((((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_I2S) == RCC_PERIPHCLK_I2S)
        || (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_SAI_PLLI2S) == RCC_PERIPHCLK_SAI_PLLI2S)
        || (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_PLLI2S) == RCC_PERIPHCLK_PLLI2S)) {
        /* check for Parameters */
        assert_param(IS_RCC_PLLI2SN_VALUE(PeriphClkInit->PLLI2S.PLLI2SN));

        /* Disable the PLLI2S */
        __HAL_RCC_PLLI2S_DISABLE();
        /* Get tick */
        tickstart = HAL_GetTick();
        /* Wait till PLLI2S is disabled */
        while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLI2SRDY) != RESET) {
            if ((HAL_GetTick() - tickstart) > PLLI2S_TIMEOUT_VALUE) {
                /* return in case of Timeout detected */
                return HAL_TIMEOUT;
            }
        }

        /*---------------------- I2S configuration -------------------------------*/
        /* In Case of I2S Clock Configuration through PLLI2S, PLLI2SR must be added
          only for I2S configuration */
        if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_I2S) == (RCC_PERIPHCLK_I2S)) {
            /* check for Parameters */
            assert_param(IS_RCC_PLLI2SR_VALUE(PeriphClkInit->PLLI2S.PLLI2SR));
            /* Configure the PLLI2S division factors */
            /* PLLI2S_VCO = f(VCO clock) = f(PLLI2S clock input) x (PLLI2SN/PLLM) */
            /* I2SCLK = f(PLLI2S clock output) = f(VCO clock) / PLLI2SR */
            __HAL_RCC_PLLI2S_CONFIG(PeriphClkInit->PLLI2S.PLLI2SN, PeriphClkInit->PLLI2S.PLLI2SR);
        }

        /*---------------------------- SAI configuration -------------------------*/
        /* In Case of SAI Clock Configuration through PLLI2S, PLLI2SQ and PLLI2S_DIVQ must
           be added only for SAI configuration */
        if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_SAI_PLLI2S) == (RCC_PERIPHCLK_SAI_PLLI2S)) {
            /* Check the PLLI2S division factors */
            assert_param(IS_RCC_PLLI2SQ_VALUE(PeriphClkInit->PLLI2S.PLLI2SQ));
            assert_param(IS_RCC_PLLI2S_DIVQ_VALUE(PeriphClkInit->PLLI2SDivQ));

            /* Read PLLI2SR value from PLLI2SCFGR register (this value is not need for SAI configuration) */
            tmpreg1 = ((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SR) >> RCC_PLLI2SCFGR_PLLI2SR_Pos);
            /* Configure the PLLI2S division factors */
            /* PLLI2S_VCO Input  = PLL_SOURCE/PLLM */
            /* PLLI2S_VCO Output = PLLI2S_VCO Input * PLLI2SN */
            /* SAI_CLK(first level) = PLLI2S_VCO Output/PLLI2SQ */
            __HAL_RCC_PLLI2S_SAICLK_CONFIG(PeriphClkInit->PLLI2S.PLLI2SN, PeriphClkInit->PLLI2S.PLLI2SQ, tmpreg1);
            /* SAI_CLK_x = SAI_CLK(first level)/PLLI2SDIVQ */
            __HAL_RCC_PLLI2S_PLLSAICLKDIVQ_CONFIG(PeriphClkInit->PLLI2SDivQ);
        }

        /*----------------- In Case of PLLI2S is just selected  -----------------*/
        if ((PeriphClkInit->PeriphClockSelection & RCC_PERIPHCLK_PLLI2S) == RCC_PERIPHCLK_PLLI2S) {
            /* Check for Parameters */
            assert_param(IS_RCC_PLLI2SQ_VALUE(PeriphClkInit->PLLI2S.PLLI2SQ));
            assert_param(IS_RCC_PLLI2SR_VALUE(PeriphClkInit->PLLI2S.PLLI2SR));

            /* Configure the PLLI2S multiplication and division factors */
            __HAL_RCC_PLLI2S_SAICLK_CONFIG(
                PeriphClkInit->PLLI2S.PLLI2SN, PeriphClkInit->PLLI2S.PLLI2SQ, PeriphClkInit->PLLI2S.PLLI2SR);
        }

        /* Enable the PLLI2S */
        __HAL_RCC_PLLI2S_ENABLE();
        /* Get tick */
        tickstart = HAL_GetTick();
        /* Wait till PLLI2S is ready */
        while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLI2SRDY) == RESET) {
            if ((HAL_GetTick() - tickstart) > PLLI2S_TIMEOUT_VALUE) {
                /* return in case of Timeout detected */
                return HAL_TIMEOUT;
            }
        }
    }
    /*--------------------------------------------------------------------------*/

    /*----------------------- SAI/LTDC Configuration (PLLSAI) ------------------*/
    /*----------------------- Common configuration SAI/LTDC --------------------*/
    /* In Case of SAI, LTDC or CLK48 Clock Configuration through PLLSAI, PLLSAIN division
       factor is common parameters for these peripherals */
    if ((((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_SAI_PLLSAI) == RCC_PERIPHCLK_SAI_PLLSAI)
        || (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_LTDC) == RCC_PERIPHCLK_LTDC)
        || ((((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_CLK48) == RCC_PERIPHCLK_CLK48)
            && (PeriphClkInit->Clk48ClockSelection == RCC_CLK48CLKSOURCE_PLLSAIP))) {
        /* Check the PLLSAI division factors */
        assert_param(IS_RCC_PLLSAIN_VALUE(PeriphClkInit->PLLSAI.PLLSAIN));

        /* Disable PLLSAI Clock */
        __HAL_RCC_PLLSAI_DISABLE();
        /* Get tick */
        tickstart = HAL_GetTick();
        /* Wait till PLLSAI is disabled */
        while (__HAL_RCC_PLLSAI_GET_FLAG() != RESET) {
            if ((HAL_GetTick() - tickstart) > PLLSAI_TIMEOUT_VALUE) {
                /* return in case of Timeout detected */
                return HAL_TIMEOUT;
            }
        }

        /*---------------------------- SAI configuration -------------------------*/
        /* In Case of SAI Clock Configuration through PLLSAI, PLLSAIQ and PLLSAI_DIVQ must
           be added only for SAI configuration */
        if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_SAI_PLLSAI) == (RCC_PERIPHCLK_SAI_PLLSAI)) {
            assert_param(IS_RCC_PLLSAIQ_VALUE(PeriphClkInit->PLLSAI.PLLSAIQ));
            assert_param(IS_RCC_PLLSAI_DIVQ_VALUE(PeriphClkInit->PLLSAIDivQ));

            /* Read PLLSAIP value from PLLSAICFGR register (this value is not needed for SAI configuration) */
            pllsaip = ((((RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIP) >> RCC_PLLSAICFGR_PLLSAIP_Pos) + 1U) << 1U);
            /* Read PLLSAIR value from PLLSAICFGR register (this value is not need for SAI configuration) */
            pllsair = ((RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIR) >> RCC_PLLSAICFGR_PLLSAIR_Pos);
            /* PLLSAI_VCO Input  = PLL_SOURCE/PLLM */
            /* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAIN */
            /* SAI_CLK(first level) = PLLSAI_VCO Output/PLLSAIQ */
            __HAL_RCC_PLLSAI_CONFIG(PeriphClkInit->PLLSAI.PLLSAIN, pllsaip, PeriphClkInit->PLLSAI.PLLSAIQ, pllsair);
            /* SAI_CLK_x = SAI_CLK(first level)/PLLSAIDIVQ */
            __HAL_RCC_PLLSAI_PLLSAICLKDIVQ_CONFIG(PeriphClkInit->PLLSAIDivQ);
        }

        /*---------------------------- LTDC configuration ------------------------*/
        if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_LTDC) == (RCC_PERIPHCLK_LTDC)) {
            assert_param(IS_RCC_PLLSAIR_VALUE(PeriphClkInit->PLLSAI.PLLSAIR));
            assert_param(IS_RCC_PLLSAI_DIVR_VALUE(PeriphClkInit->PLLSAIDivR));

            /* Read PLLSAIP value from PLLSAICFGR register (this value is not needed for SAI configuration) */
            pllsaip = ((((RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIP) >> RCC_PLLSAICFGR_PLLSAIP_Pos) + 1U) << 1U);
            /* Read PLLSAIQ value from PLLSAICFGR register (this value is not need for SAI configuration) */
            pllsaiq = ((RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIQ) >> RCC_PLLSAICFGR_PLLSAIQ_Pos);
            /* PLLSAI_VCO Input  = PLL_SOURCE/PLLM */
            /* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAIN */
            /* LTDC_CLK(first level) = PLLSAI_VCO Output/PLLSAIR */
            __HAL_RCC_PLLSAI_CONFIG(PeriphClkInit->PLLSAI.PLLSAIN, pllsaip, pllsaiq, PeriphClkInit->PLLSAI.PLLSAIR);
            /* LTDC_CLK = LTDC_CLK(first level)/PLLSAIDIVR */
            __HAL_RCC_PLLSAI_PLLSAICLKDIVR_CONFIG(PeriphClkInit->PLLSAIDivR);
        }

        /*---------------------------- CLK48 configuration ------------------------*/
        /* Configure the PLLSAI when it is used as clock source for CLK48 */
        if ((((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_CLK48) == (RCC_PERIPHCLK_CLK48))
            && (PeriphClkInit->Clk48ClockSelection == RCC_CLK48CLKSOURCE_PLLSAIP)) {
            assert_param(IS_RCC_PLLSAIP_VALUE(PeriphClkInit->PLLSAI.PLLSAIP));

            /* Read PLLSAIQ value from PLLSAICFGR register (this value is not need for SAI configuration) */
            pllsaiq = ((RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIQ) >> RCC_PLLSAICFGR_PLLSAIQ_Pos);
            /* Read PLLSAIR value from PLLSAICFGR register (this value is not need for SAI configuration) */
            pllsair = ((RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIR) >> RCC_PLLSAICFGR_PLLSAIR_Pos);
            /* PLLSAI_VCO Input  = PLL_SOURCE/PLLM */
            /* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAIN */
            /* CLK48_CLK(first level) = PLLSAI_VCO Output/PLLSAIP */
            __HAL_RCC_PLLSAI_CONFIG(PeriphClkInit->PLLSAI.PLLSAIN, PeriphClkInit->PLLSAI.PLLSAIP, pllsaiq, pllsair);
        }

        /* Enable PLLSAI Clock */
        __HAL_RCC_PLLSAI_ENABLE();
        /* Get tick */
        tickstart = HAL_GetTick();
        /* Wait till PLLSAI is ready */
        while (__HAL_RCC_PLLSAI_GET_FLAG() == RESET) {
            if ((HAL_GetTick() - tickstart) > PLLSAI_TIMEOUT_VALUE) {
                /* return in case of Timeout detected */
                return HAL_TIMEOUT;
            }
        }
    }

    /*--------------------------------------------------------------------------*/

    /*---------------------------- RTC configuration ---------------------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_RTC) == (RCC_PERIPHCLK_RTC)) {
        /* Check for RTC Parameters used to output RTCCLK */
        assert_param(IS_RCC_RTCCLKSOURCE(PeriphClkInit->RTCClockSelection));

        /* Enable Power Clock*/
        __HAL_RCC_PWR_CLK_ENABLE();

        /* Enable write access to Backup domain */
        PWR->CR |= PWR_CR_DBP;

        /* Get tick */
        tickstart = HAL_GetTick();

        while ((PWR->CR & PWR_CR_DBP) == RESET) {
            if ((HAL_GetTick() - tickstart) > RCC_DBP_TIMEOUT_VALUE) {
                return HAL_TIMEOUT;
            }
        }
        /* Reset the Backup domain only if the RTC Clock source selection is modified from reset value */
        tmpreg1 = (RCC->BDCR & RCC_BDCR_RTCSEL);
        if ((tmpreg1 != 0x00000000U) && ((tmpreg1) != (PeriphClkInit->RTCClockSelection & RCC_BDCR_RTCSEL))) {
            /* Store the content of BDCR register before the reset of Backup Domain */
            tmpreg1 = (RCC->BDCR & ~(RCC_BDCR_RTCSEL));
            /* RTC Clock selection can be changed only if the Backup Domain is reset */
            __HAL_RCC_BACKUPRESET_FORCE();
            __HAL_RCC_BACKUPRESET_RELEASE();
            /* Restore the Content of BDCR register */
            RCC->BDCR = tmpreg1;

            /* Wait for LSE reactivation if LSE was enable prior to Backup Domain reset */
            if (HAL_IS_BIT_SET(RCC->BDCR, RCC_BDCR_LSEON)) {
                /* Get tick */
                tickstart = HAL_GetTick();

                /* Wait till LSE is ready */
                while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) == RESET) {
                    if ((HAL_GetTick() - tickstart) > RCC_LSE_TIMEOUT_VALUE) {
                        return HAL_TIMEOUT;
                    }
                }
            }
        }
        __HAL_RCC_RTC_CONFIG(PeriphClkInit->RTCClockSelection);
    }
    /*--------------------------------------------------------------------------*/

    /*---------------------------- TIM configuration ---------------------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_TIM) == (RCC_PERIPHCLK_TIM)) {
        __HAL_RCC_TIMCLKPRESCALER(PeriphClkInit->TIMPresSelection);
    }
    return HAL_OK;
}

/**
 * @brief  Configures the RCC_PeriphCLKInitTypeDef according to the internal
 * RCC configuration registers.
 * @param  PeriphClkInit pointer to an RCC_PeriphCLKInitTypeDef structure that
 *         will be configured.
 * @retval None
 */
void HAL_RCCEx_GetPeriphCLKConfig(RCC_PeriphCLKInitTypeDef* PeriphClkInit)
{
    uint32_t tempreg;

    /* Set all possible values for the extended clock type parameter------------*/
    PeriphClkInit->PeriphClockSelection = RCC_PERIPHCLK_I2S | RCC_PERIPHCLK_SAI_PLLSAI | RCC_PERIPHCLK_SAI_PLLI2S
                                          | RCC_PERIPHCLK_LTDC | RCC_PERIPHCLK_TIM | RCC_PERIPHCLK_RTC
                                          | RCC_PERIPHCLK_CLK48 | RCC_PERIPHCLK_SDIO;

    /* Get the PLLI2S Clock configuration --------------------------------------*/
    PeriphClkInit->PLLI2S.PLLI2SN =
        (uint32_t)((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SN) >> RCC_PLLI2SCFGR_PLLI2SN_Pos);
    PeriphClkInit->PLLI2S.PLLI2SR =
        (uint32_t)((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SR) >> RCC_PLLI2SCFGR_PLLI2SR_Pos);
    PeriphClkInit->PLLI2S.PLLI2SQ =
        (uint32_t)((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SQ) >> RCC_PLLI2SCFGR_PLLI2SQ_Pos);
    /* Get the PLLSAI Clock configuration --------------------------------------*/
    PeriphClkInit->PLLSAI.PLLSAIN =
        (uint32_t)((RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIN) >> RCC_PLLSAICFGR_PLLSAIN_Pos);
    PeriphClkInit->PLLSAI.PLLSAIR =
        (uint32_t)((RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIR) >> RCC_PLLSAICFGR_PLLSAIR_Pos);
    PeriphClkInit->PLLSAI.PLLSAIQ =
        (uint32_t)((RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIQ) >> RCC_PLLSAICFGR_PLLSAIQ_Pos);
    /* Get the PLLSAI/PLLI2S division factors ----------------------------------*/
    PeriphClkInit->PLLI2SDivQ = (uint32_t)((RCC->DCKCFGR & RCC_DCKCFGR_PLLI2SDIVQ) >> RCC_DCKCFGR_PLLI2SDIVQ_Pos);
    PeriphClkInit->PLLSAIDivQ = (uint32_t)((RCC->DCKCFGR & RCC_DCKCFGR_PLLSAIDIVQ) >> RCC_DCKCFGR_PLLSAIDIVQ_Pos);
    PeriphClkInit->PLLSAIDivR = (uint32_t)(RCC->DCKCFGR & RCC_DCKCFGR_PLLSAIDIVR);
    /* Get the RTC Clock configuration -----------------------------------------*/
    tempreg = (RCC->CFGR & RCC_CFGR_RTCPRE);
    PeriphClkInit->RTCClockSelection = (uint32_t)((tempreg) | (RCC->BDCR & RCC_BDCR_RTCSEL));

    /* Get the CLK48 clock configuration -------------------------------------*/
    PeriphClkInit->Clk48ClockSelection = __HAL_RCC_GET_CLK48_SOURCE();

    /* Get the SDIO clock configuration ----------------------------------------*/
    PeriphClkInit->SdioClockSelection = __HAL_RCC_GET_SDIO_SOURCE();

    if ((RCC->DCKCFGR & RCC_DCKCFGR_TIMPRE) == RESET) {
        PeriphClkInit->TIMPresSelection = RCC_TIMPRES_DESACTIVATED;
    }
    else {
        PeriphClkInit->TIMPresSelection = RCC_TIMPRES_ACTIVATED;
    }
}

/**
 * @brief  Return the peripheral clock frequency for a given peripheral(SAI..)
 * @note   Return 0 if peripheral clock identifier not managed by this API
 * @param  PeriphClk Peripheral clock identifier
 *         This parameter can be one of the following values:
 *            @arg RCC_PERIPHCLK_I2S: I2S peripheral clock
 * @retval Frequency in KHz
 */
uint32_t HAL_RCCEx_GetPeriphCLKFreq(uint32_t PeriphClk)
{
    /* This variable used to store the I2S clock frequency (value in Hz) */
    uint32_t frequency = 0U;
    /* This variable used to store the VCO Input (value in Hz) */
    uint32_t vcoinput = 0U;
    uint32_t srcclk = 0U;
    /* This variable used to store the VCO Output (value in Hz) */
    uint32_t vcooutput = 0U;
    switch (PeriphClk) {
        case RCC_PERIPHCLK_I2S: {
            /* Get the current I2S source */
            srcclk = __HAL_RCC_GET_I2S_SOURCE();
            switch (srcclk) {
                /* Check if I2S clock selection is External clock mapped on the I2S_CKIN pin used as I2S clock */
                case RCC_I2SCLKSOURCE_EXT: {
                    /* Set the I2S clock to the external clock  value */
                    frequency = EXTERNAL_CLOCK_VALUE;
                    break;
                }
                /* Check if I2S clock selection is PLLI2S VCO output clock divided by PLLI2SR used as I2S clock */
                case RCC_I2SCLKSOURCE_PLLI2S: {
                    /* Configure the PLLI2S division factor */
                    /* PLLI2S_VCO Input  = PLL_SOURCE/PLLI2SM */
                    if ((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLSOURCE_HSE) {
                        /* Get the I2S source clock value */
                        vcoinput = (uint32_t)(HSE_VALUE / (uint32_t)(RCC->PLLCFGR & RCC_PLLCFGR_PLLM));
                    }
                    else {
                        /* Get the I2S source clock value */
                        vcoinput = (uint32_t)(HSI_VALUE / (uint32_t)(RCC->PLLCFGR & RCC_PLLCFGR_PLLM));
                    }

                    /* PLLI2S_VCO Output = PLLI2S_VCO Input * PLLI2SN */
                    vcooutput = (uint32_t)(
                        vcoinput
                        * (((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SN) >> 6U) & (RCC_PLLI2SCFGR_PLLI2SN >> 6U)));
                    /* I2S_CLK = PLLI2S_VCO Output/PLLI2SR */
                    frequency = (uint32_t)(
                        vcooutput
                        / (((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SR) >> 28U) & (RCC_PLLI2SCFGR_PLLI2SR >> 28U)));
                    break;
                }
                    /* Clock not enabled for I2S*/
                default: {
                    frequency = 0U;
                    break;
                }
            }
            break;
        }
    }
    return frequency;
}
#    endif /* STM32F469xx || STM32F479xx */

#    if defined(STM32F412Zx) || defined(STM32F412Vx) || defined(STM32F412Rx) || defined(STM32F412Cx) \
        || defined(STM32F413xx) || defined(STM32F423xx)
/**
 * @brief  Initializes the RCC extended peripherals clocks according to the specified
 *         parameters in the RCC_PeriphCLKInitTypeDef.
 * @param  PeriphClkInit pointer to an RCC_PeriphCLKInitTypeDef structure that
 *         contains the configuration information for the Extended Peripherals
 *         clocks(I2S, LTDC RTC and TIM).
 *
 * @note   Care must be taken when HAL_RCCEx_PeriphCLKConfig() is used to select
 *         the RTC clock source; in this case the Backup domain will be reset in
 *         order to modify the RTC Clock source, as consequence RTC registers (including
 *         the backup registers) and RCC_BDCR register are set to their reset values.
 *
 * @retval HAL status
 */
HAL_StatusTypeDef HAL_RCCEx_PeriphCLKConfig(RCC_PeriphCLKInitTypeDef* PeriphClkInit)
{
    uint32_t tickstart = 0U;
    uint32_t tmpreg1 = 0U;
#        if defined(STM32F413xx) || defined(STM32F423xx)
    uint32_t plli2sq = 0U;
#        endif /* STM32F413xx || STM32F423xx */
    uint32_t plli2sused = 0U;

    /* Check the peripheral clock selection parameters */
    assert_param(IS_RCC_PERIPHCLOCK(PeriphClkInit->PeriphClockSelection));

    /*----------------------------------- I2S APB1 configuration ---------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_I2S_APB1) == (RCC_PERIPHCLK_I2S_APB1)) {
        /* Check the parameters */
        assert_param(IS_RCC_I2SAPB1CLKSOURCE(PeriphClkInit->I2sApb1ClockSelection));

        /* Configure I2S Clock source */
        __HAL_RCC_I2S_APB1_CONFIG(PeriphClkInit->I2sApb1ClockSelection);
        /* Enable the PLLI2S when it's used as clock source for I2S */
        if (PeriphClkInit->I2sApb1ClockSelection == RCC_I2SAPB1CLKSOURCE_PLLI2S) {
            plli2sused = 1U;
        }
    }
    /*--------------------------------------------------------------------------*/

    /*----------------------------------- I2S APB2 configuration ---------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_I2S_APB2) == (RCC_PERIPHCLK_I2S_APB2)) {
        /* Check the parameters */
        assert_param(IS_RCC_I2SAPB2CLKSOURCE(PeriphClkInit->I2sApb2ClockSelection));

        /* Configure I2S Clock source */
        __HAL_RCC_I2S_APB2_CONFIG(PeriphClkInit->I2sApb2ClockSelection);
        /* Enable the PLLI2S when it's used as clock source for I2S */
        if (PeriphClkInit->I2sApb2ClockSelection == RCC_I2SAPB2CLKSOURCE_PLLI2S) {
            plli2sused = 1U;
        }
    }
    /*--------------------------------------------------------------------------*/

#        if defined(STM32F413xx) || defined(STM32F423xx)
    /*----------------------- SAI1 Block A configuration -----------------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_SAIA) == (RCC_PERIPHCLK_SAIA)) {
        /* Check the parameters */
        assert_param(IS_RCC_SAIACLKSOURCE(PeriphClkInit->SaiAClockSelection));

        /* Configure SAI1 Clock source */
        __HAL_RCC_SAI_BLOCKACLKSOURCE_CONFIG(PeriphClkInit->SaiAClockSelection);
        /* Enable the PLLI2S when it's used as clock source for SAI */
        if (PeriphClkInit->SaiAClockSelection == RCC_SAIACLKSOURCE_PLLI2SR) {
            plli2sused = 1U;
        }
        /* Enable the PLLSAI when it's used as clock source for SAI */
        if (PeriphClkInit->SaiAClockSelection == RCC_SAIACLKSOURCE_PLLR) {
            /* Check for PLL/DIVR parameters */
            assert_param(IS_RCC_PLL_DIVR_VALUE(PeriphClkInit->PLLDivR));

            /* SAI_CLK_x = SAI_CLK(first level)/PLLDIVR */
            __HAL_RCC_PLL_PLLSAICLKDIVR_CONFIG(PeriphClkInit->PLLDivR);
        }
    }
    /*--------------------------------------------------------------------------*/

    /*---------------------- SAI1 Block B configuration ------------------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_SAIB) == (RCC_PERIPHCLK_SAIB)) {
        /* Check the parameters */
        assert_param(IS_RCC_SAIBCLKSOURCE(PeriphClkInit->SaiBClockSelection));

        /* Configure SAI1 Clock source */
        __HAL_RCC_SAI_BLOCKBCLKSOURCE_CONFIG(PeriphClkInit->SaiBClockSelection);
        /* Enable the PLLI2S when it's used as clock source for SAI */
        if (PeriphClkInit->SaiBClockSelection == RCC_SAIBCLKSOURCE_PLLI2SR) {
            plli2sused = 1U;
        }
        /* Enable the PLLSAI when it's used as clock source for SAI */
        if (PeriphClkInit->SaiBClockSelection == RCC_SAIBCLKSOURCE_PLLR) {
            /* Check for PLL/DIVR parameters */
            assert_param(IS_RCC_PLL_DIVR_VALUE(PeriphClkInit->PLLDivR));

            /* SAI_CLK_x = SAI_CLK(first level)/PLLDIVR */
            __HAL_RCC_PLL_PLLSAICLKDIVR_CONFIG(PeriphClkInit->PLLDivR);
        }
    }
    /*--------------------------------------------------------------------------*/
#        endif /* STM32F413xx || STM32F423xx */

    /*------------------------------------ RTC configuration -------------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_RTC) == (RCC_PERIPHCLK_RTC)) {
        /* Check for RTC Parameters used to output RTCCLK */
        assert_param(IS_RCC_RTCCLKSOURCE(PeriphClkInit->RTCClockSelection));

        /* Enable Power Clock*/
        __HAL_RCC_PWR_CLK_ENABLE();

        /* Enable write access to Backup domain */
        PWR->CR |= PWR_CR_DBP;

        /* Get tick */
        tickstart = HAL_GetTick();

        while ((PWR->CR & PWR_CR_DBP) == RESET) {
            if ((HAL_GetTick() - tickstart) > RCC_DBP_TIMEOUT_VALUE) {
                return HAL_TIMEOUT;
            }
        }
        /* Reset the Backup domain only if the RTC Clock source selection is modified from reset value */
        tmpreg1 = (RCC->BDCR & RCC_BDCR_RTCSEL);
        if ((tmpreg1 != 0x00000000U) && ((tmpreg1) != (PeriphClkInit->RTCClockSelection & RCC_BDCR_RTCSEL))) {
            /* Store the content of BDCR register before the reset of Backup Domain */
            tmpreg1 = (RCC->BDCR & ~(RCC_BDCR_RTCSEL));
            /* RTC Clock selection can be changed only if the Backup Domain is reset */
            __HAL_RCC_BACKUPRESET_FORCE();
            __HAL_RCC_BACKUPRESET_RELEASE();
            /* Restore the Content of BDCR register */
            RCC->BDCR = tmpreg1;

            /* Wait for LSE reactivation if LSE was enable prior to Backup Domain reset */
            if (HAL_IS_BIT_SET(RCC->BDCR, RCC_BDCR_LSEON)) {
                /* Get tick */
                tickstart = HAL_GetTick();

                /* Wait till LSE is ready */
                while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) == RESET) {
                    if ((HAL_GetTick() - tickstart) > RCC_LSE_TIMEOUT_VALUE) {
                        return HAL_TIMEOUT;
                    }
                }
            }
        }
        __HAL_RCC_RTC_CONFIG(PeriphClkInit->RTCClockSelection);
    }
    /*--------------------------------------------------------------------------*/

    /*------------------------------------ TIM configuration -------------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_TIM) == (RCC_PERIPHCLK_TIM)) {
        /* Configure Timer Prescaler */
        __HAL_RCC_TIMCLKPRESCALER(PeriphClkInit->TIMPresSelection);
    }
    /*--------------------------------------------------------------------------*/

    /*------------------------------------- FMPI2C1 Configuration --------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_FMPI2C1) == RCC_PERIPHCLK_FMPI2C1) {
        /* Check the parameters */
        assert_param(IS_RCC_FMPI2C1CLKSOURCE(PeriphClkInit->Fmpi2c1ClockSelection));

        /* Configure the FMPI2C1 clock source */
        __HAL_RCC_FMPI2C1_CONFIG(PeriphClkInit->Fmpi2c1ClockSelection);
    }
    /*--------------------------------------------------------------------------*/

    /*------------------------------------- CLK48 Configuration ----------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_CLK48) == RCC_PERIPHCLK_CLK48) {
        /* Check the parameters */
        assert_param(IS_RCC_CLK48CLKSOURCE(PeriphClkInit->Clk48ClockSelection));

        /* Configure the SDIO clock source */
        __HAL_RCC_CLK48_CONFIG(PeriphClkInit->Clk48ClockSelection);

        /* Enable the PLLI2S when it's used as clock source for CLK48 */
        if (PeriphClkInit->Clk48ClockSelection == RCC_CLK48CLKSOURCE_PLLI2SQ) {
            plli2sused = 1U;
        }
    }
    /*--------------------------------------------------------------------------*/

    /*------------------------------------- SDIO Configuration -----------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_SDIO) == RCC_PERIPHCLK_SDIO) {
        /* Check the parameters */
        assert_param(IS_RCC_SDIOCLKSOURCE(PeriphClkInit->SdioClockSelection));

        /* Configure the SDIO clock source */
        __HAL_RCC_SDIO_CONFIG(PeriphClkInit->SdioClockSelection);
    }
    /*--------------------------------------------------------------------------*/

    /*-------------------------------------- PLLI2S Configuration --------------*/
    /* PLLI2S is configured when a peripheral will use it as source clock : I2S on APB1 or
       I2S on APB2*/
    if ((plli2sused == 1U) || (PeriphClkInit->PeriphClockSelection == RCC_PERIPHCLK_PLLI2S)) {
        /* Disable the PLLI2S */
        __HAL_RCC_PLLI2S_DISABLE();
        /* Get tick */
        tickstart = HAL_GetTick();
        /* Wait till PLLI2S is disabled */
        while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLI2SRDY) != RESET) {
            if ((HAL_GetTick() - tickstart) > PLLI2S_TIMEOUT_VALUE) {
                /* return in case of Timeout detected */
                return HAL_TIMEOUT;
            }
        }

        /* check for common PLLI2S Parameters */
        assert_param(IS_RCC_PLLI2SCLKSOURCE(PeriphClkInit->PLLI2SSelection));
        assert_param(IS_RCC_PLLI2SM_VALUE(PeriphClkInit->PLLI2S.PLLI2SM));
        assert_param(IS_RCC_PLLI2SN_VALUE(PeriphClkInit->PLLI2S.PLLI2SN));
        /*-------------------- Set the PLL I2S clock -----------------------------*/
        __HAL_RCC_PLL_I2S_CONFIG(PeriphClkInit->PLLI2SSelection);

        /*------- In Case of PLLI2S is selected as source clock for I2S ----------*/
        if (((((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_I2S_APB1) == RCC_PERIPHCLK_I2S_APB1)
             && (PeriphClkInit->I2sApb1ClockSelection == RCC_I2SAPB1CLKSOURCE_PLLI2S))
            || ((((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_I2S_APB2) == RCC_PERIPHCLK_I2S_APB2)
                && (PeriphClkInit->I2sApb2ClockSelection == RCC_I2SAPB2CLKSOURCE_PLLI2S))
            || ((((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_CLK48) == RCC_PERIPHCLK_CLK48)
                && (PeriphClkInit->Clk48ClockSelection == RCC_CLK48CLKSOURCE_PLLI2SQ))
            || ((((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_SDIO) == RCC_PERIPHCLK_SDIO)
                && (PeriphClkInit->SdioClockSelection == RCC_SDIOCLKSOURCE_CLK48)
                && (PeriphClkInit->Clk48ClockSelection == RCC_CLK48CLKSOURCE_PLLI2SQ))) {
            /* check for Parameters */
            assert_param(IS_RCC_PLLI2SR_VALUE(PeriphClkInit->PLLI2S.PLLI2SR));
            assert_param(IS_RCC_PLLI2SQ_VALUE(PeriphClkInit->PLLI2S.PLLI2SQ));

            /* Configure the PLLI2S division factors */
            /* PLLI2S_VCO = f(VCO clock) = f(PLLI2S clock input) * (PLLI2SN/PLLI2SM)*/
            /* I2SCLK = f(PLLI2S clock output) = f(VCO clock) / PLLI2SR */
            __HAL_RCC_PLLI2S_CONFIG(PeriphClkInit->PLLI2S.PLLI2SM,
                                    PeriphClkInit->PLLI2S.PLLI2SN,
                                    PeriphClkInit->PLLI2S.PLLI2SQ,
                                    PeriphClkInit->PLLI2S.PLLI2SR);
        }

#        if defined(STM32F413xx) || defined(STM32F423xx)
        /*------- In Case of PLLI2S is selected as source clock for SAI ----------*/
        if (((((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_SAIA) == RCC_PERIPHCLK_SAIA)
             && (PeriphClkInit->SaiAClockSelection == RCC_SAIACLKSOURCE_PLLI2SR))
            || ((((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_SAIB) == RCC_PERIPHCLK_SAIB)
                && (PeriphClkInit->SaiBClockSelection == RCC_SAIBCLKSOURCE_PLLI2SR))) {
            /* Check for PLLI2S Parameters */
            assert_param(IS_RCC_PLLI2SR_VALUE(PeriphClkInit->PLLI2S.PLLI2SR));
            /* Check for PLLI2S/DIVR parameters */
            assert_param(IS_RCC_PLLI2S_DIVR_VALUE(PeriphClkInit->PLLI2SDivR));

            /* Read PLLI2SQ value from PLLI2SCFGR register (this value is not needed for SAI configuration) */
            plli2sq = ((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SQ) >> RCC_PLLI2SCFGR_PLLI2SQ_Pos);
            /* Configure the PLLI2S division factors */
            /* PLLI2S_VCO Input  = PLL_SOURCE/PLLI2SM */
            /* PLLI2S_VCO Output = PLLI2S_VCO Input * PLLI2SN */
            /* SAI_CLK(first level) = PLLI2S_VCO Output/PLLI2SQ */
            __HAL_RCC_PLLI2S_CONFIG(
                PeriphClkInit->PLLI2S.PLLI2SM, PeriphClkInit->PLLI2S.PLLI2SN, plli2sq, PeriphClkInit->PLLI2S.PLLI2SR);

            /* SAI_CLK_x = SAI_CLK(first level)/PLLI2SDIVR */
            __HAL_RCC_PLLI2S_PLLSAICLKDIVR_CONFIG(PeriphClkInit->PLLI2SDivR);
        }
#        endif /* STM32F413xx || STM32F423xx */

        /*----------------- In Case of PLLI2S is just selected  ------------------*/
        if ((PeriphClkInit->PeriphClockSelection & RCC_PERIPHCLK_PLLI2S) == RCC_PERIPHCLK_PLLI2S) {
            /* Check for Parameters */
            assert_param(IS_RCC_PLLI2SR_VALUE(PeriphClkInit->PLLI2S.PLLI2SR));
            assert_param(IS_RCC_PLLI2SQ_VALUE(PeriphClkInit->PLLI2S.PLLI2SQ));

            /* Configure the PLLI2S division factors */
            /* PLLI2S_VCO = f(VCO clock) = f(PLLI2S clock input) * (PLLI2SN/PLLI2SM)*/
            /* SPDIFRXCLK = f(PLLI2S clock output) = f(VCO clock) / PLLI2SP */
            __HAL_RCC_PLLI2S_CONFIG(PeriphClkInit->PLLI2S.PLLI2SM,
                                    PeriphClkInit->PLLI2S.PLLI2SN,
                                    PeriphClkInit->PLLI2S.PLLI2SQ,
                                    PeriphClkInit->PLLI2S.PLLI2SR);
        }

        /* Enable the PLLI2S */
        __HAL_RCC_PLLI2S_ENABLE();
        /* Get tick */
        tickstart = HAL_GetTick();
        /* Wait till PLLI2S is ready */
        while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLI2SRDY) == RESET) {
            if ((HAL_GetTick() - tickstart) > PLLI2S_TIMEOUT_VALUE) {
                /* return in case of Timeout detected */
                return HAL_TIMEOUT;
            }
        }
    }
    /*--------------------------------------------------------------------------*/

    /*-------------------- DFSDM1 clock source configuration -------------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_DFSDM1) == RCC_PERIPHCLK_DFSDM1) {
        /* Check the parameters */
        assert_param(IS_RCC_DFSDM1CLKSOURCE(PeriphClkInit->Dfsdm1ClockSelection));

        /* Configure the DFSDM1 interface clock source */
        __HAL_RCC_DFSDM1_CONFIG(PeriphClkInit->Dfsdm1ClockSelection);
    }
    /*--------------------------------------------------------------------------*/

    /*-------------------- DFSDM1 Audio clock source configuration -------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_DFSDM1_AUDIO) == RCC_PERIPHCLK_DFSDM1_AUDIO) {
        /* Check the parameters */
        assert_param(IS_RCC_DFSDM1AUDIOCLKSOURCE(PeriphClkInit->Dfsdm1AudioClockSelection));

        /* Configure the DFSDM1 Audio interface clock source */
        __HAL_RCC_DFSDM1AUDIO_CONFIG(PeriphClkInit->Dfsdm1AudioClockSelection);
    }
    /*--------------------------------------------------------------------------*/

#        if defined(STM32F413xx) || defined(STM32F423xx)
    /*-------------------- DFSDM2 clock source configuration -------------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_DFSDM2) == RCC_PERIPHCLK_DFSDM2) {
        /* Check the parameters */
        assert_param(IS_RCC_DFSDM2CLKSOURCE(PeriphClkInit->Dfsdm2ClockSelection));

        /* Configure the DFSDM1 interface clock source */
        __HAL_RCC_DFSDM2_CONFIG(PeriphClkInit->Dfsdm2ClockSelection);
    }
    /*--------------------------------------------------------------------------*/

    /*-------------------- DFSDM2 Audio clock source configuration -------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_DFSDM2_AUDIO) == RCC_PERIPHCLK_DFSDM2_AUDIO) {
        /* Check the parameters */
        assert_param(IS_RCC_DFSDM2AUDIOCLKSOURCE(PeriphClkInit->Dfsdm2AudioClockSelection));

        /* Configure the DFSDM1 Audio interface clock source */
        __HAL_RCC_DFSDM2AUDIO_CONFIG(PeriphClkInit->Dfsdm2AudioClockSelection);
    }
    /*--------------------------------------------------------------------------*/

    /*---------------------------- LPTIM1 Configuration ------------------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_LPTIM1) == RCC_PERIPHCLK_LPTIM1) {
        /* Check the parameters */
        assert_param(IS_RCC_LPTIM1CLKSOURCE(PeriphClkInit->Lptim1ClockSelection));

        /* Configure the LPTIM1 clock source */
        __HAL_RCC_LPTIM1_CONFIG(PeriphClkInit->Lptim1ClockSelection);
    }
    /*--------------------------------------------------------------------------*/
#        endif /* STM32F413xx || STM32F423xx */

    return HAL_OK;
}

/**
 * @brief  Get the RCC_PeriphCLKInitTypeDef according to the internal
 *         RCC configuration registers.
 * @param  PeriphClkInit pointer to an RCC_PeriphCLKInitTypeDef structure that
 *         will be configured.
 * @retval None
 */
void HAL_RCCEx_GetPeriphCLKConfig(RCC_PeriphCLKInitTypeDef* PeriphClkInit)
{
    uint32_t tempreg;

    /* Set all possible values for the extended clock type parameter------------*/
#        if defined(STM32F413xx) || defined(STM32F423xx)
    PeriphClkInit->PeriphClockSelection = RCC_PERIPHCLK_I2S_APB1 | RCC_PERIPHCLK_I2S_APB2 | RCC_PERIPHCLK_TIM
                                          | RCC_PERIPHCLK_RTC | RCC_PERIPHCLK_FMPI2C1 | RCC_PERIPHCLK_CLK48
                                          | RCC_PERIPHCLK_SDIO | RCC_PERIPHCLK_DFSDM1 | RCC_PERIPHCLK_DFSDM1_AUDIO
                                          | RCC_PERIPHCLK_DFSDM2 | RCC_PERIPHCLK_DFSDM2_AUDIO | RCC_PERIPHCLK_LPTIM1
                                          | RCC_PERIPHCLK_SAIA | RCC_PERIPHCLK_SAIB;
#        else /* STM32F412Zx || STM32F412Vx || STM32F412Rx || STM32F412Cx */
    PeriphClkInit->PeriphClockSelection = RCC_PERIPHCLK_I2S_APB1 | RCC_PERIPHCLK_I2S_APB2 | RCC_PERIPHCLK_TIM
                                          | RCC_PERIPHCLK_RTC | RCC_PERIPHCLK_FMPI2C1 | RCC_PERIPHCLK_CLK48
                                          | RCC_PERIPHCLK_SDIO | RCC_PERIPHCLK_DFSDM1 | RCC_PERIPHCLK_DFSDM1_AUDIO;
#        endif /* STM32F413xx || STM32F423xx */



    /* Get the PLLI2S Clock configuration --------------------------------------*/
    PeriphClkInit->PLLI2S.PLLI2SM =
        (uint32_t)((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SM) >> RCC_PLLI2SCFGR_PLLI2SM_Pos);
    PeriphClkInit->PLLI2S.PLLI2SN =
        (uint32_t)((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SN) >> RCC_PLLI2SCFGR_PLLI2SN_Pos);
    PeriphClkInit->PLLI2S.PLLI2SQ =
        (uint32_t)((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SQ) >> RCC_PLLI2SCFGR_PLLI2SQ_Pos);
    PeriphClkInit->PLLI2S.PLLI2SR =
        (uint32_t)((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SR) >> RCC_PLLI2SCFGR_PLLI2SR_Pos);
#        if defined(STM32F413xx) || defined(STM32F423xx)
    /* Get the PLL/PLLI2S division factors -------------------------------------*/
    PeriphClkInit->PLLI2SDivR = (uint32_t)((RCC->DCKCFGR & RCC_DCKCFGR_PLLI2SDIVR) >> RCC_DCKCFGR_PLLI2SDIVR_Pos);
    PeriphClkInit->PLLDivR = (uint32_t)((RCC->DCKCFGR & RCC_DCKCFGR_PLLDIVR) >> RCC_DCKCFGR_PLLDIVR_Pos);
#        endif /* STM32F413xx || STM32F423xx */

    /* Get the I2S APB1 clock configuration ------------------------------------*/
    PeriphClkInit->I2sApb1ClockSelection = __HAL_RCC_GET_I2S_APB1_SOURCE();

    /* Get the I2S APB2 clock configuration ------------------------------------*/
    PeriphClkInit->I2sApb2ClockSelection = __HAL_RCC_GET_I2S_APB2_SOURCE();

    /* Get the RTC Clock configuration -----------------------------------------*/
    tempreg = (RCC->CFGR & RCC_CFGR_RTCPRE);
    PeriphClkInit->RTCClockSelection = (uint32_t)((tempreg) | (RCC->BDCR & RCC_BDCR_RTCSEL));

    /* Get the FMPI2C1 clock configuration -------------------------------------*/
    PeriphClkInit->Fmpi2c1ClockSelection = __HAL_RCC_GET_FMPI2C1_SOURCE();

    /* Get the CLK48 clock configuration ---------------------------------------*/
    PeriphClkInit->Clk48ClockSelection = __HAL_RCC_GET_CLK48_SOURCE();

    /* Get the SDIO clock configuration ----------------------------------------*/
    PeriphClkInit->SdioClockSelection = __HAL_RCC_GET_SDIO_SOURCE();

    /* Get the DFSDM1 clock configuration --------------------------------------*/
    PeriphClkInit->Dfsdm1ClockSelection = __HAL_RCC_GET_DFSDM1_SOURCE();

    /* Get the DFSDM1 Audio clock configuration --------------------------------*/
    PeriphClkInit->Dfsdm1AudioClockSelection = __HAL_RCC_GET_DFSDM1AUDIO_SOURCE();

#        if defined(STM32F413xx) || defined(STM32F423xx)
    /* Get the DFSDM2 clock configuration --------------------------------------*/
    PeriphClkInit->Dfsdm2ClockSelection = __HAL_RCC_GET_DFSDM2_SOURCE();

    /* Get the DFSDM2 Audio clock configuration --------------------------------*/
    PeriphClkInit->Dfsdm2AudioClockSelection = __HAL_RCC_GET_DFSDM2AUDIO_SOURCE();

    /* Get the LPTIM1 clock configuration --------------------------------------*/
    PeriphClkInit->Lptim1ClockSelection = __HAL_RCC_GET_LPTIM1_SOURCE();

    /* Get the SAI1 Block Aclock configuration ---------------------------------*/
    PeriphClkInit->SaiAClockSelection = __HAL_RCC_GET_SAI_BLOCKA_SOURCE();

    /* Get the SAI1 Block B clock configuration --------------------------------*/
    PeriphClkInit->SaiBClockSelection = __HAL_RCC_GET_SAI_BLOCKB_SOURCE();
#        endif /* STM32F413xx || STM32F423xx */

    /* Get the TIM Prescaler configuration -------------------------------------*/
    if ((RCC->DCKCFGR & RCC_DCKCFGR_TIMPRE) == RESET) {
        PeriphClkInit->TIMPresSelection = RCC_TIMPRES_DESACTIVATED;
    }
    else {
        PeriphClkInit->TIMPresSelection = RCC_TIMPRES_ACTIVATED;
    }
}

/**
 * @brief  Return the peripheral clock frequency for a given peripheral(I2S..)
 * @note   Return 0 if peripheral clock identifier not managed by this API
 * @param  PeriphClk Peripheral clock identifier
 *         This parameter can be one of the following values:
 *            @arg RCC_PERIPHCLK_I2S_APB1: I2S APB1 peripheral clock
 *            @arg RCC_PERIPHCLK_I2S_APB2: I2S APB2 peripheral clock
 * @retval Frequency in KHz
 */
uint32_t HAL_RCCEx_GetPeriphCLKFreq(uint32_t PeriphClk)
{
    /* This variable used to store the I2S clock frequency (value in Hz) */
    uint32_t frequency = 0U;
    /* This variable used to store the VCO Input (value in Hz) */
    uint32_t vcoinput = 0U;
    uint32_t srcclk = 0U;
    /* This variable used to store the VCO Output (value in Hz) */
    uint32_t vcooutput = 0U;
    switch (PeriphClk) {
        case RCC_PERIPHCLK_I2S_APB1: {
            /* Get the current I2S source */
            srcclk = __HAL_RCC_GET_I2S_APB1_SOURCE();
            switch (srcclk) {
                /* Check if I2S clock selection is External clock mapped on the I2S_CKIN pin used as I2S clock */
                case RCC_I2SAPB1CLKSOURCE_EXT: {
                    /* Set the I2S clock to the external clock  value */
                    frequency = EXTERNAL_CLOCK_VALUE;
                    break;
                }
                /* Check if I2S clock selection is PLLI2S VCO output clock divided by PLLI2SR used as I2S clock */
                case RCC_I2SAPB1CLKSOURCE_PLLI2S: {
                    if ((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SSRC) == RCC_PLLI2SCFGR_PLLI2SSRC) {
                        /* Get the I2S source clock value */
                        vcoinput =
                            (uint32_t)(EXTERNAL_CLOCK_VALUE / (uint32_t)(RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SM));
                    }
                    else {
                        /* Configure the PLLI2S division factor */
                        /* PLLI2S_VCO Input  = PLL_SOURCE/PLLI2SM */
                        if ((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLSOURCE_HSE) {
                            /* Get the I2S source clock value */
                            vcoinput = (uint32_t)(HSE_VALUE / (uint32_t)(RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SM));
                        }
                        else {
                            /* Get the I2S source clock value */
                            vcoinput = (uint32_t)(HSI_VALUE / (uint32_t)(RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SM));
                        }
                    }
                    /* PLLI2S_VCO Output = PLLI2S_VCO Input * PLLI2SN */
                    vcooutput = (uint32_t)(
                        vcoinput
                        * (((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SN) >> 6U) & (RCC_PLLI2SCFGR_PLLI2SN >> 6U)));
                    /* I2S_CLK = PLLI2S_VCO Output/PLLI2SR */
                    frequency = (uint32_t)(
                        vcooutput
                        / (((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SR) >> 28U) & (RCC_PLLI2SCFGR_PLLI2SR >> 28U)));
                    break;
                }
                /* Check if I2S clock selection is PLL VCO Output divided by PLLR used as I2S clock */
                case RCC_I2SAPB1CLKSOURCE_PLLR: {
                    /* Configure the PLL division factor R */
                    /* PLL_VCO Input  = PLL_SOURCE/PLLM */
                    if ((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLSOURCE_HSE) {
                        /* Get the I2S source clock value */
                        vcoinput = (uint32_t)(HSE_VALUE / (uint32_t)(RCC->PLLCFGR & RCC_PLLCFGR_PLLM));
                    }
                    else {
                        /* Get the I2S source clock value */
                        vcoinput = (uint32_t)(HSI_VALUE / (uint32_t)(RCC->PLLCFGR & RCC_PLLCFGR_PLLM));
                    }

                    /* PLL_VCO Output = PLL_VCO Input * PLLN */
                    vcooutput =
                        (uint32_t)(vcoinput * (((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6U) & (RCC_PLLCFGR_PLLN >> 6U)));
                    /* I2S_CLK = PLL_VCO Output/PLLR */
                    frequency = (uint32_t)(vcooutput
                                           / (((RCC->PLLCFGR & RCC_PLLCFGR_PLLR) >> 28U) & (RCC_PLLCFGR_PLLR >> 28U)));
                    break;
                }
                /* Check if I2S clock selection is HSI or HSE depending from PLL source Clock */
                case RCC_I2SAPB1CLKSOURCE_PLLSRC: {
                    if ((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLSOURCE_HSE) {
                        frequency = HSE_VALUE;
                    }
                    else {
                        frequency = HSI_VALUE;
                    }
                    break;
                }
                    /* Clock not enabled for I2S*/
                default: {
                    frequency = 0U;
                    break;
                }
            }
            break;
        }
        case RCC_PERIPHCLK_I2S_APB2: {
            /* Get the current I2S source */
            srcclk = __HAL_RCC_GET_I2S_APB2_SOURCE();
            switch (srcclk) {
                    /* Check if I2S clock selection is External clock mapped on the I2S_CKIN pin used as I2S clock */
                case RCC_I2SAPB2CLKSOURCE_EXT: {
                    /* Set the I2S clock to the external clock  value */
                    frequency = EXTERNAL_CLOCK_VALUE;
                    break;
                }
                    /* Check if I2S clock selection is PLLI2S VCO output clock divided by PLLI2SR used as I2S clock */
                case RCC_I2SAPB2CLKSOURCE_PLLI2S: {
                    if ((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SSRC) == RCC_PLLI2SCFGR_PLLI2SSRC) {
                        /* Get the I2S source clock value */
                        vcoinput =
                            (uint32_t)(EXTERNAL_CLOCK_VALUE / (uint32_t)(RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SM));
                    }
                    else {
                        /* Configure the PLLI2S division factor */
                        /* PLLI2S_VCO Input  = PLL_SOURCE/PLLI2SM */
                        if ((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLSOURCE_HSE) {
                            /* Get the I2S source clock value */
                            vcoinput = (uint32_t)(HSE_VALUE / (uint32_t)(RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SM));
                        }
                        else {
                            /* Get the I2S source clock value */
                            vcoinput = (uint32_t)(HSI_VALUE / (uint32_t)(RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SM));
                        }
                    }
                    /* PLLI2S_VCO Output = PLLI2S_VCO Input * PLLI2SN */
                    vcooutput = (uint32_t)(
                        vcoinput
                        * (((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SN) >> 6U) & (RCC_PLLI2SCFGR_PLLI2SN >> 6U)));
                    /* I2S_CLK = PLLI2S_VCO Output/PLLI2SR */
                    frequency = (uint32_t)(
                        vcooutput
                        / (((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SR) >> 28U) & (RCC_PLLI2SCFGR_PLLI2SR >> 28U)));
                    break;
                }
                    /* Check if I2S clock selection is PLL VCO Output divided by PLLR used as I2S clock */
                case RCC_I2SAPB2CLKSOURCE_PLLR: {
                    /* Configure the PLL division factor R */
                    /* PLL_VCO Input  = PLL_SOURCE/PLLM */
                    if ((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLSOURCE_HSE) {
                        /* Get the I2S source clock value */
                        vcoinput = (uint32_t)(HSE_VALUE / (uint32_t)(RCC->PLLCFGR & RCC_PLLCFGR_PLLM));
                    }
                    else {
                        /* Get the I2S source clock value */
                        vcoinput = (uint32_t)(HSI_VALUE / (uint32_t)(RCC->PLLCFGR & RCC_PLLCFGR_PLLM));
                    }

                    /* PLL_VCO Output = PLL_VCO Input * PLLN */
                    vcooutput =
                        (uint32_t)(vcoinput * (((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6U) & (RCC_PLLCFGR_PLLN >> 6U)));
                    /* I2S_CLK = PLL_VCO Output/PLLR */
                    frequency = (uint32_t)(vcooutput
                                           / (((RCC->PLLCFGR & RCC_PLLCFGR_PLLR) >> 28U) & (RCC_PLLCFGR_PLLR >> 28U)));
                    break;
                }
                    /* Check if I2S clock selection is HSI or HSE depending from PLL source Clock */
                case RCC_I2SAPB2CLKSOURCE_PLLSRC: {
                    if ((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLSOURCE_HSE) {
                        frequency = HSE_VALUE;
                    }
                    else {
                        frequency = HSI_VALUE;
                    }
                    break;
                }
                /* Clock not enabled for I2S*/
                default: {
                    frequency = 0U;
                    break;
                }
            }
            break;
        }
    }
    return frequency;
}
#    endif /* STM32F412Zx || STM32F412Vx || STM32F412Rx || STM32F412Cx || STM32F413xx || STM32F423xx */

#    if defined(STM32F410Tx) || defined(STM32F410Cx) || defined(STM32F410Rx)
/**
 * @brief  Initializes the RCC extended peripherals clocks according to the specified parameters in the
 *         RCC_PeriphCLKInitTypeDef.
 * @param  PeriphClkInit pointer to an RCC_PeriphCLKInitTypeDef structure that
 *         contains the configuration information for the Extended Peripherals clocks(I2S and RTC clocks).
 *
 * @note   A caution to be taken when HAL_RCCEx_PeriphCLKConfig() is used to select RTC clock selection, in this case
 *         the Reset of Backup domain will be applied in order to modify the RTC Clock source as consequence all backup
 *        domain (RTC and RCC_BDCR register expect BKPSRAM) will be reset
 *
 * @retval HAL status
 */
HAL_StatusTypeDef HAL_RCCEx_PeriphCLKConfig(RCC_PeriphCLKInitTypeDef* PeriphClkInit)
{
    uint32_t tickstart = 0U;
    uint32_t tmpreg1 = 0U;

    /* Check the parameters */
    assert_param(IS_RCC_PERIPHCLOCK(PeriphClkInit->PeriphClockSelection));

    /*---------------------------- RTC configuration ---------------------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_RTC) == (RCC_PERIPHCLK_RTC)) {
        /* Check for RTC Parameters used to output RTCCLK */
        assert_param(IS_RCC_RTCCLKSOURCE(PeriphClkInit->RTCClockSelection));

        /* Enable Power Clock*/
        __HAL_RCC_PWR_CLK_ENABLE();

        /* Enable write access to Backup domain */
        PWR->CR |= PWR_CR_DBP;

        /* Get tick */
        tickstart = HAL_GetTick();

        while ((PWR->CR & PWR_CR_DBP) == RESET) {
            if ((HAL_GetTick() - tickstart) > RCC_DBP_TIMEOUT_VALUE) {
                return HAL_TIMEOUT;
            }
        }
        /* Reset the Backup domain only if the RTC Clock source selection is modified from reset value */
        tmpreg1 = (RCC->BDCR & RCC_BDCR_RTCSEL);
        if ((tmpreg1 != 0x00000000U) && ((tmpreg1) != (PeriphClkInit->RTCClockSelection & RCC_BDCR_RTCSEL))) {
            /* Store the content of BDCR register before the reset of Backup Domain */
            tmpreg1 = (RCC->BDCR & ~(RCC_BDCR_RTCSEL));
            /* RTC Clock selection can be changed only if the Backup Domain is reset */
            __HAL_RCC_BACKUPRESET_FORCE();
            __HAL_RCC_BACKUPRESET_RELEASE();
            /* Restore the Content of BDCR register */
            RCC->BDCR = tmpreg1;

            /* Wait for LSE reactivation if LSE was enable prior to Backup Domain reset */
            if (HAL_IS_BIT_SET(RCC->BDCR, RCC_BDCR_LSEON)) {
                /* Get tick */
                tickstart = HAL_GetTick();

                /* Wait till LSE is ready */
                while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) == RESET) {
                    if ((HAL_GetTick() - tickstart) > RCC_LSE_TIMEOUT_VALUE) {
                        return HAL_TIMEOUT;
                    }
                }
            }
        }
        __HAL_RCC_RTC_CONFIG(PeriphClkInit->RTCClockSelection);
    }
    /*--------------------------------------------------------------------------*/

    /*---------------------------- TIM configuration ---------------------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_TIM) == (RCC_PERIPHCLK_TIM)) {
        __HAL_RCC_TIMCLKPRESCALER(PeriphClkInit->TIMPresSelection);
    }
    /*--------------------------------------------------------------------------*/

    /*---------------------------- FMPI2C1 Configuration -----------------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_FMPI2C1) == RCC_PERIPHCLK_FMPI2C1) {
        /* Check the parameters */
        assert_param(IS_RCC_FMPI2C1CLKSOURCE(PeriphClkInit->Fmpi2c1ClockSelection));

        /* Configure the FMPI2C1 clock source */
        __HAL_RCC_FMPI2C1_CONFIG(PeriphClkInit->Fmpi2c1ClockSelection);
    }
    /*--------------------------------------------------------------------------*/

    /*---------------------------- LPTIM1 Configuration ------------------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_LPTIM1) == RCC_PERIPHCLK_LPTIM1) {
        /* Check the parameters */
        assert_param(IS_RCC_LPTIM1CLKSOURCE(PeriphClkInit->Lptim1ClockSelection));

        /* Configure the LPTIM1 clock source */
        __HAL_RCC_LPTIM1_CONFIG(PeriphClkInit->Lptim1ClockSelection);
    }

    /*---------------------------- I2S Configuration ---------------------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_I2S) == RCC_PERIPHCLK_I2S) {
        /* Check the parameters */
        assert_param(IS_RCC_I2SAPBCLKSOURCE(PeriphClkInit->I2SClockSelection));

        /* Configure the I2S clock source */
        __HAL_RCC_I2S_CONFIG(PeriphClkInit->I2SClockSelection);
    }

    return HAL_OK;
}

/**
 * @brief  Configures the RCC_OscInitStruct according to the internal
 * RCC configuration registers.
 * @param  PeriphClkInit pointer to an RCC_PeriphCLKInitTypeDef structure that
 * will be configured.
 * @retval None
 */
void HAL_RCCEx_GetPeriphCLKConfig(RCC_PeriphCLKInitTypeDef* PeriphClkInit)
{
    uint32_t tempreg;

    /* Set all possible values for the extended clock type parameter------------*/
    PeriphClkInit->PeriphClockSelection =
        RCC_PERIPHCLK_FMPI2C1 | RCC_PERIPHCLK_LPTIM1 | RCC_PERIPHCLK_TIM | RCC_PERIPHCLK_RTC;

    tempreg = (RCC->CFGR & RCC_CFGR_RTCPRE);
    PeriphClkInit->RTCClockSelection = (uint32_t)((tempreg) | (RCC->BDCR & RCC_BDCR_RTCSEL));

    if ((RCC->DCKCFGR & RCC_DCKCFGR_TIMPRE) == RESET) {
        PeriphClkInit->TIMPresSelection = RCC_TIMPRES_DESACTIVATED;
    }
    else {
        PeriphClkInit->TIMPresSelection = RCC_TIMPRES_ACTIVATED;
    }
    /* Get the FMPI2C1 clock configuration -------------------------------------*/
    PeriphClkInit->Fmpi2c1ClockSelection = __HAL_RCC_GET_FMPI2C1_SOURCE();

    /* Get the I2S clock configuration -----------------------------------------*/
    PeriphClkInit->I2SClockSelection = __HAL_RCC_GET_I2S_SOURCE();
}
/**
 * @brief  Return the peripheral clock frequency for a given peripheral(SAI..)
 * @note   Return 0 if peripheral clock identifier not managed by this API
 * @param  PeriphClk Peripheral clock identifier
 *         This parameter can be one of the following values:
 *            @arg RCC_PERIPHCLK_I2S: I2S peripheral clock
 * @retval Frequency in KHz
 */
uint32_t HAL_RCCEx_GetPeriphCLKFreq(uint32_t PeriphClk)
{
    /* This variable used to store the I2S clock frequency (value in Hz) */
    uint32_t frequency = 0U;
    /* This variable used to store the VCO Input (value in Hz) */
    uint32_t vcoinput = 0U;
    uint32_t srcclk = 0U;
    /* This variable used to store the VCO Output (value in Hz) */
    uint32_t vcooutput = 0U;
    switch (PeriphClk) {
        case RCC_PERIPHCLK_I2S: {
            /* Get the current I2S source */
            srcclk = __HAL_RCC_GET_I2S_SOURCE();
            switch (srcclk) {
                /* Check if I2S clock selection is External clock mapped on the I2S_CKIN pin used as I2S clock */
                case RCC_I2SAPBCLKSOURCE_EXT: {
                    /* Set the I2S clock to the external clock  value */
                    frequency = EXTERNAL_CLOCK_VALUE;
                    break;
                }
                /* Check if I2S clock selection is PLL VCO Output divided by PLLR used as I2S clock */
                case RCC_I2SAPBCLKSOURCE_PLLR: {
                    /* Configure the PLL division factor R */
                    /* PLL_VCO Input  = PLL_SOURCE/PLLM */
                    if ((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLSOURCE_HSE) {
                        /* Get the I2S source clock value */
                        vcoinput = (uint32_t)(HSE_VALUE / (uint32_t)(RCC->PLLCFGR & RCC_PLLCFGR_PLLM));
                    }
                    else {
                        /* Get the I2S source clock value */
                        vcoinput = (uint32_t)(HSI_VALUE / (uint32_t)(RCC->PLLCFGR & RCC_PLLCFGR_PLLM));
                    }

                    /* PLL_VCO Output = PLL_VCO Input * PLLN */
                    vcooutput =
                        (uint32_t)(vcoinput * (((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6U) & (RCC_PLLCFGR_PLLN >> 6U)));
                    /* I2S_CLK = PLL_VCO Output/PLLR */
                    frequency = (uint32_t)(vcooutput
                                           / (((RCC->PLLCFGR & RCC_PLLCFGR_PLLR) >> 28U) & (RCC_PLLCFGR_PLLR >> 28U)));
                    break;
                }
                /* Check if I2S clock selection is HSI or HSE depending from PLL source Clock */
                case RCC_I2SAPBCLKSOURCE_PLLSRC: {
                    if ((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLSOURCE_HSE) {
                        frequency = HSE_VALUE;
                    }
                    else {
                        frequency = HSI_VALUE;
                    }
                    break;
                }
                    /* Clock not enabled for I2S*/
                default: {
                    frequency = 0U;
                    break;
                }
            }
            break;
        }
    }
    return frequency;
}
#    endif /* STM32F410Tx || STM32F410Cx || STM32F410Rx */

#    if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)
/**
 * @brief  Initializes the RCC extended peripherals clocks according to the specified
 *         parameters in the RCC_PeriphCLKInitTypeDef.
 * @param  PeriphClkInit pointer to an RCC_PeriphCLKInitTypeDef structure that
 *         contains the configuration information for the Extended Peripherals
 *         clocks(I2S, SAI, LTDC RTC and TIM).
 *
 * @note   Care must be taken when HAL_RCCEx_PeriphCLKConfig() is used to select
 *         the RTC clock source; in this case the Backup domain will be reset in
 *         order to modify the RTC Clock source, as consequence RTC registers (including
 *         the backup registers) and RCC_BDCR register are set to their reset values.
 *
 * @retval HAL status
 */
HAL_StatusTypeDef HAL_RCCEx_PeriphCLKConfig(RCC_PeriphCLKInitTypeDef* PeriphClkInit)
{
    uint32_t tickstart = 0U;
    uint32_t tmpreg1 = 0U;

    /* Check the parameters */
    assert_param(IS_RCC_PERIPHCLOCK(PeriphClkInit->PeriphClockSelection));

    /*----------------------- SAI/I2S Configuration (PLLI2S) -------------------*/
    /*----------------------- Common configuration SAI/I2S ---------------------*/
    /* In Case of SAI or I2S Clock Configuration through PLLI2S, PLLI2SN division
       factor is common parameters for both peripherals */
    if ((((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_I2S) == RCC_PERIPHCLK_I2S)
        || (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_SAI_PLLI2S) == RCC_PERIPHCLK_SAI_PLLI2S)
        || (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_PLLI2S) == RCC_PERIPHCLK_PLLI2S)) {
        /* check for Parameters */
        assert_param(IS_RCC_PLLI2SN_VALUE(PeriphClkInit->PLLI2S.PLLI2SN));

        /* Disable the PLLI2S */
        __HAL_RCC_PLLI2S_DISABLE();
        /* Get tick */
        tickstart = HAL_GetTick();
        /* Wait till PLLI2S is disabled */
        while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLI2SRDY) != RESET) {
            if ((HAL_GetTick() - tickstart) > PLLI2S_TIMEOUT_VALUE) {
                /* return in case of Timeout detected */
                return HAL_TIMEOUT;
            }
        }

        /*---------------------------- I2S configuration -------------------------*/
        /* In Case of I2S Clock Configuration through PLLI2S, PLLI2SR must be added
          only for I2S configuration */
        if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_I2S) == (RCC_PERIPHCLK_I2S)) {
            /* check for Parameters */
            assert_param(IS_RCC_PLLI2SR_VALUE(PeriphClkInit->PLLI2S.PLLI2SR));
            /* Configure the PLLI2S division factors */
            /* PLLI2S_VCO = f(VCO clock) = f(PLLI2S clock input) * (PLLI2SN/PLLM) */
            /* I2SCLK = f(PLLI2S clock output) = f(VCO clock) / PLLI2SR */
            __HAL_RCC_PLLI2S_CONFIG(PeriphClkInit->PLLI2S.PLLI2SN, PeriphClkInit->PLLI2S.PLLI2SR);
        }

        /*---------------------------- SAI configuration -------------------------*/
        /* In Case of SAI Clock Configuration through PLLI2S, PLLI2SQ and PLLI2S_DIVQ must
           be added only for SAI configuration */
        if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_SAI_PLLI2S) == (RCC_PERIPHCLK_SAI_PLLI2S)) {
            /* Check the PLLI2S division factors */
            assert_param(IS_RCC_PLLI2SQ_VALUE(PeriphClkInit->PLLI2S.PLLI2SQ));
            assert_param(IS_RCC_PLLI2S_DIVQ_VALUE(PeriphClkInit->PLLI2SDivQ));

            /* Read PLLI2SR value from PLLI2SCFGR register (this value is not need for SAI configuration) */
            tmpreg1 = ((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SR) >> RCC_PLLI2SCFGR_PLLI2SR_Pos);
            /* Configure the PLLI2S division factors */
            /* PLLI2S_VCO Input  = PLL_SOURCE/PLLM */
            /* PLLI2S_VCO Output = PLLI2S_VCO Input * PLLI2SN */
            /* SAI_CLK(first level) = PLLI2S_VCO Output/PLLI2SQ */
            __HAL_RCC_PLLI2S_SAICLK_CONFIG(PeriphClkInit->PLLI2S.PLLI2SN, PeriphClkInit->PLLI2S.PLLI2SQ, tmpreg1);
            /* SAI_CLK_x = SAI_CLK(first level)/PLLI2SDIVQ */
            __HAL_RCC_PLLI2S_PLLSAICLKDIVQ_CONFIG(PeriphClkInit->PLLI2SDivQ);
        }

        /*----------------- In Case of PLLI2S is just selected  -----------------*/
        if ((PeriphClkInit->PeriphClockSelection & RCC_PERIPHCLK_PLLI2S) == RCC_PERIPHCLK_PLLI2S) {
            /* Check for Parameters */
            assert_param(IS_RCC_PLLI2SQ_VALUE(PeriphClkInit->PLLI2S.PLLI2SQ));
            assert_param(IS_RCC_PLLI2SR_VALUE(PeriphClkInit->PLLI2S.PLLI2SR));

            /* Configure the PLLI2S multiplication and division factors */
            __HAL_RCC_PLLI2S_SAICLK_CONFIG(
                PeriphClkInit->PLLI2S.PLLI2SN, PeriphClkInit->PLLI2S.PLLI2SQ, PeriphClkInit->PLLI2S.PLLI2SR);
        }

        /* Enable the PLLI2S */
        __HAL_RCC_PLLI2S_ENABLE();
        /* Get tick */
        tickstart = HAL_GetTick();
        /* Wait till PLLI2S is ready */
        while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLI2SRDY) == RESET) {
            if ((HAL_GetTick() - tickstart) > PLLI2S_TIMEOUT_VALUE) {
                /* return in case of Timeout detected */
                return HAL_TIMEOUT;
            }
        }
    }
    /*--------------------------------------------------------------------------*/

    /*----------------------- SAI/LTDC Configuration (PLLSAI) ------------------*/
    /*----------------------- Common configuration SAI/LTDC --------------------*/
    /* In Case of SAI or LTDC Clock Configuration through PLLSAI, PLLSAIN division
       factor is common parameters for both peripherals */
    if ((((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_SAI_PLLSAI) == RCC_PERIPHCLK_SAI_PLLSAI)
        || (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_LTDC) == RCC_PERIPHCLK_LTDC)) {
        /* Check the PLLSAI division factors */
        assert_param(IS_RCC_PLLSAIN_VALUE(PeriphClkInit->PLLSAI.PLLSAIN));

        /* Disable PLLSAI Clock */
        __HAL_RCC_PLLSAI_DISABLE();
        /* Get tick */
        tickstart = HAL_GetTick();
        /* Wait till PLLSAI is disabled */
        while (__HAL_RCC_PLLSAI_GET_FLAG() != RESET) {
            if ((HAL_GetTick() - tickstart) > PLLSAI_TIMEOUT_VALUE) {
                /* return in case of Timeout detected */
                return HAL_TIMEOUT;
            }
        }

        /*---------------------------- SAI configuration -------------------------*/
        /* In Case of SAI Clock Configuration through PLLSAI, PLLSAIQ and PLLSAI_DIVQ must
           be added only for SAI configuration */
        if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_SAI_PLLSAI) == (RCC_PERIPHCLK_SAI_PLLSAI)) {
            assert_param(IS_RCC_PLLSAIQ_VALUE(PeriphClkInit->PLLSAI.PLLSAIQ));
            assert_param(IS_RCC_PLLSAI_DIVQ_VALUE(PeriphClkInit->PLLSAIDivQ));

            /* Read PLLSAIR value from PLLSAICFGR register (this value is not need for SAI configuration) */
            tmpreg1 = ((RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIR) >> RCC_PLLSAICFGR_PLLSAIR_Pos);
            /* PLLSAI_VCO Input  = PLL_SOURCE/PLLM */
            /* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAIN */
            /* SAI_CLK(first level) = PLLSAI_VCO Output/PLLSAIQ */
            __HAL_RCC_PLLSAI_CONFIG(PeriphClkInit->PLLSAI.PLLSAIN, PeriphClkInit->PLLSAI.PLLSAIQ, tmpreg1);
            /* SAI_CLK_x = SAI_CLK(first level)/PLLSAIDIVQ */
            __HAL_RCC_PLLSAI_PLLSAICLKDIVQ_CONFIG(PeriphClkInit->PLLSAIDivQ);
        }

        /*---------------------------- LTDC configuration ------------------------*/
        if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_LTDC) == (RCC_PERIPHCLK_LTDC)) {
            assert_param(IS_RCC_PLLSAIR_VALUE(PeriphClkInit->PLLSAI.PLLSAIR));
            assert_param(IS_RCC_PLLSAI_DIVR_VALUE(PeriphClkInit->PLLSAIDivR));

            /* Read PLLSAIR value from PLLSAICFGR register (this value is not need for SAI configuration) */
            tmpreg1 = ((RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIQ) >> RCC_PLLSAICFGR_PLLSAIQ_Pos);
            /* PLLSAI_VCO Input  = PLL_SOURCE/PLLM */
            /* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAIN */
            /* LTDC_CLK(first level) = PLLSAI_VCO Output/PLLSAIR */
            __HAL_RCC_PLLSAI_CONFIG(PeriphClkInit->PLLSAI.PLLSAIN, tmpreg1, PeriphClkInit->PLLSAI.PLLSAIR);
            /* LTDC_CLK = LTDC_CLK(first level)/PLLSAIDIVR */
            __HAL_RCC_PLLSAI_PLLSAICLKDIVR_CONFIG(PeriphClkInit->PLLSAIDivR);
        }
        /* Enable PLLSAI Clock */
        __HAL_RCC_PLLSAI_ENABLE();
        /* Get tick */
        tickstart = HAL_GetTick();
        /* Wait till PLLSAI is ready */
        while (__HAL_RCC_PLLSAI_GET_FLAG() == RESET) {
            if ((HAL_GetTick() - tickstart) > PLLSAI_TIMEOUT_VALUE) {
                /* return in case of Timeout detected */
                return HAL_TIMEOUT;
            }
        }
    }
    /*--------------------------------------------------------------------------*/

    /*---------------------------- RTC configuration ---------------------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_RTC) == (RCC_PERIPHCLK_RTC)) {
        /* Check for RTC Parameters used to output RTCCLK */
        assert_param(IS_RCC_RTCCLKSOURCE(PeriphClkInit->RTCClockSelection));

        /* Enable Power Clock*/
        __HAL_RCC_PWR_CLK_ENABLE();

        /* Enable write access to Backup domain */
        PWR->CR |= PWR_CR_DBP;

        /* Get tick */
        tickstart = HAL_GetTick();

        while ((PWR->CR & PWR_CR_DBP) == RESET) {
            if ((HAL_GetTick() - tickstart) > RCC_DBP_TIMEOUT_VALUE) {
                return HAL_TIMEOUT;
            }
        }
        /* Reset the Backup domain only if the RTC Clock source selection is modified from reset value */
        tmpreg1 = (RCC->BDCR & RCC_BDCR_RTCSEL);
        if ((tmpreg1 != 0x00000000U) && ((tmpreg1) != (PeriphClkInit->RTCClockSelection & RCC_BDCR_RTCSEL))) {
            /* Store the content of BDCR register before the reset of Backup Domain */
            tmpreg1 = (RCC->BDCR & ~(RCC_BDCR_RTCSEL));
            /* RTC Clock selection can be changed only if the Backup Domain is reset */
            __HAL_RCC_BACKUPRESET_FORCE();
            __HAL_RCC_BACKUPRESET_RELEASE();
            /* Restore the Content of BDCR register */
            RCC->BDCR = tmpreg1;

            /* Wait for LSE reactivation if LSE was enable prior to Backup Domain reset */
            if (HAL_IS_BIT_SET(RCC->BDCR, RCC_BDCR_LSEON)) {
                /* Get tick */
                tickstart = HAL_GetTick();

                /* Wait till LSE is ready */
                while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) == RESET) {
                    if ((HAL_GetTick() - tickstart) > RCC_LSE_TIMEOUT_VALUE) {
                        return HAL_TIMEOUT;
                    }
                }
            }
        }
        __HAL_RCC_RTC_CONFIG(PeriphClkInit->RTCClockSelection);
    }
    /*--------------------------------------------------------------------------*/

    /*---------------------------- TIM configuration ---------------------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_TIM) == (RCC_PERIPHCLK_TIM)) {
        __HAL_RCC_TIMCLKPRESCALER(PeriphClkInit->TIMPresSelection);
    }
    return HAL_OK;
}

/**
 * @brief  Configures the PeriphClkInit according to the internal
 * RCC configuration registers.
 * @param  PeriphClkInit pointer to an RCC_PeriphCLKInitTypeDef structure that
 *         will be configured.
 * @retval None
 */
void HAL_RCCEx_GetPeriphCLKConfig(RCC_PeriphCLKInitTypeDef* PeriphClkInit)
{
    uint32_t tempreg;

    /* Set all possible values for the extended clock type parameter------------*/
    PeriphClkInit->PeriphClockSelection = RCC_PERIPHCLK_I2S | RCC_PERIPHCLK_SAI_PLLSAI | RCC_PERIPHCLK_SAI_PLLI2S
                                          | RCC_PERIPHCLK_LTDC | RCC_PERIPHCLK_TIM | RCC_PERIPHCLK_RTC;

    /* Get the PLLI2S Clock configuration -----------------------------------------------*/
    PeriphClkInit->PLLI2S.PLLI2SN =
        (uint32_t)((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SN) >> RCC_PLLI2SCFGR_PLLI2SN_Pos);
    PeriphClkInit->PLLI2S.PLLI2SR =
        (uint32_t)((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SR) >> RCC_PLLI2SCFGR_PLLI2SR_Pos);
    PeriphClkInit->PLLI2S.PLLI2SQ =
        (uint32_t)((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SQ) >> RCC_PLLI2SCFGR_PLLI2SQ_Pos);
    /* Get the PLLSAI Clock configuration -----------------------------------------------*/
    PeriphClkInit->PLLSAI.PLLSAIN =
        (uint32_t)((RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIN) >> RCC_PLLSAICFGR_PLLSAIN_Pos);
    PeriphClkInit->PLLSAI.PLLSAIR =
        (uint32_t)((RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIR) >> RCC_PLLSAICFGR_PLLSAIR_Pos);
    PeriphClkInit->PLLSAI.PLLSAIQ =
        (uint32_t)((RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIQ) >> RCC_PLLSAICFGR_PLLSAIQ_Pos);
    /* Get the PLLSAI/PLLI2S division factors -----------------------------------------------*/
    PeriphClkInit->PLLI2SDivQ = (uint32_t)((RCC->DCKCFGR & RCC_DCKCFGR_PLLI2SDIVQ) >> RCC_DCKCFGR_PLLI2SDIVQ_Pos);
    PeriphClkInit->PLLSAIDivQ = (uint32_t)((RCC->DCKCFGR & RCC_DCKCFGR_PLLSAIDIVQ) >> RCC_DCKCFGR_PLLSAIDIVQ_Pos);
    PeriphClkInit->PLLSAIDivR = (uint32_t)(RCC->DCKCFGR & RCC_DCKCFGR_PLLSAIDIVR);
    /* Get the RTC Clock configuration -----------------------------------------------*/
    tempreg = (RCC->CFGR & RCC_CFGR_RTCPRE);
    PeriphClkInit->RTCClockSelection = (uint32_t)((tempreg) | (RCC->BDCR & RCC_BDCR_RTCSEL));

    if ((RCC->DCKCFGR & RCC_DCKCFGR_TIMPRE) == RESET) {
        PeriphClkInit->TIMPresSelection = RCC_TIMPRES_DESACTIVATED;
    }
    else {
        PeriphClkInit->TIMPresSelection = RCC_TIMPRES_ACTIVATED;
    }
}

/**
 * @brief  Return the peripheral clock frequency for a given peripheral(SAI..)
 * @note   Return 0 if peripheral clock identifier not managed by this API
 * @param  PeriphClk Peripheral clock identifier
 *         This parameter can be one of the following values:
 *            @arg RCC_PERIPHCLK_I2S: I2S peripheral clock
 * @retval Frequency in KHz
 */
uint32_t HAL_RCCEx_GetPeriphCLKFreq(uint32_t PeriphClk)
{
    /* This variable used to store the I2S clock frequency (value in Hz) */
    uint32_t frequency = 0U;
    /* This variable used to store the VCO Input (value in Hz) */
    uint32_t vcoinput = 0U;
    uint32_t srcclk = 0U;
    /* This variable used to store the VCO Output (value in Hz) */
    uint32_t vcooutput = 0U;
    switch (PeriphClk) {
        case RCC_PERIPHCLK_I2S: {
            /* Get the current I2S source */
            srcclk = __HAL_RCC_GET_I2S_SOURCE();
            switch (srcclk) {
                /* Check if I2S clock selection is External clock mapped on the I2S_CKIN pin used as I2S clock */
                case RCC_I2SCLKSOURCE_EXT: {
                    /* Set the I2S clock to the external clock  value */
                    frequency = EXTERNAL_CLOCK_VALUE;
                    break;
                }
                /* Check if I2S clock selection is PLLI2S VCO output clock divided by PLLI2SR used as I2S clock */
                case RCC_I2SCLKSOURCE_PLLI2S: {
                    /* Configure the PLLI2S division factor */
                    /* PLLI2S_VCO Input  = PLL_SOURCE/PLLM */
                    if ((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLSOURCE_HSE) {
                        /* Get the I2S source clock value */
                        vcoinput = (uint32_t)(HSE_VALUE / (uint32_t)(RCC->PLLCFGR & RCC_PLLCFGR_PLLM));
                    }
                    else {
                        /* Get the I2S source clock value */
                        vcoinput = (uint32_t)(HSI_VALUE / (uint32_t)(RCC->PLLCFGR & RCC_PLLCFGR_PLLM));
                    }

                    /* PLLI2S_VCO Output = PLLI2S_VCO Input * PLLI2SN */
                    vcooutput = (uint32_t)(
                        vcoinput
                        * (((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SN) >> 6U) & (RCC_PLLI2SCFGR_PLLI2SN >> 6U)));
                    /* I2S_CLK = PLLI2S_VCO Output/PLLI2SR */
                    frequency = (uint32_t)(
                        vcooutput
                        / (((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SR) >> 28U) & (RCC_PLLI2SCFGR_PLLI2SR >> 28U)));
                    break;
                }
                    /* Clock not enabled for I2S*/
                default: {
                    frequency = 0U;
                    break;
                }
            }
            break;
        }
    }
    return frequency;
}
#    endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx */

#    if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx) || defined(STM32F417xx) \
        || defined(STM32F401xC) || defined(STM32F401xE) || defined(STM32F411xE)
/**
 * @brief  Initializes the RCC extended peripherals clocks according to the specified parameters in the
 *         RCC_PeriphCLKInitTypeDef.
 * @param  PeriphClkInit pointer to an RCC_PeriphCLKInitTypeDef structure that
 *         contains the configuration information for the Extended Peripherals clocks(I2S and RTC clocks).
 *
 * @note   A caution to be taken when HAL_RCCEx_PeriphCLKConfig() is used to select RTC clock selection, in this case
 *         the Reset of Backup domain will be applied in order to modify the RTC Clock source as consequence all backup
 *        domain (RTC and RCC_BDCR register expect BKPSRAM) will be reset
 *
 * @retval HAL status
 */
HAL_StatusTypeDef HAL_RCCEx_PeriphCLKConfig(RCC_PeriphCLKInitTypeDef* PeriphClkInit)
{
    uint32_t tickstart = 0U;
    uint32_t tmpreg1 = 0U;

    /* Check the parameters */
    assert_param(IS_RCC_PERIPHCLOCK(PeriphClkInit->PeriphClockSelection));

    /*---------------------------- I2S configuration ---------------------------*/
    if ((((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_I2S) == RCC_PERIPHCLK_I2S)
        || (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_PLLI2S) == RCC_PERIPHCLK_PLLI2S)) {
        /* check for Parameters */
        assert_param(IS_RCC_PLLI2SR_VALUE(PeriphClkInit->PLLI2S.PLLI2SR));
        assert_param(IS_RCC_PLLI2SN_VALUE(PeriphClkInit->PLLI2S.PLLI2SN));
#        if defined(STM32F411xE)
        assert_param(IS_RCC_PLLI2SM_VALUE(PeriphClkInit->PLLI2S.PLLI2SM));
#        endif /* STM32F411xE */
        /* Disable the PLLI2S */
        __HAL_RCC_PLLI2S_DISABLE();
        /* Get tick */
        tickstart = HAL_GetTick();
        /* Wait till PLLI2S is disabled */
        while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLI2SRDY) != RESET) {
            if ((HAL_GetTick() - tickstart) > PLLI2S_TIMEOUT_VALUE) {
                /* return in case of Timeout detected */
                return HAL_TIMEOUT;
            }
        }

#        if defined(STM32F411xE)
        /* Configure the PLLI2S division factors */
        /* PLLI2S_VCO = f(VCO clock) = f(PLLI2S clock input) * (PLLI2SN/PLLI2SM) */
        /* I2SCLK = f(PLLI2S clock output) = f(VCO clock) / PLLI2SR */
        __HAL_RCC_PLLI2S_I2SCLK_CONFIG(
            PeriphClkInit->PLLI2S.PLLI2SM, PeriphClkInit->PLLI2S.PLLI2SN, PeriphClkInit->PLLI2S.PLLI2SR);
#        else
        /* Configure the PLLI2S division factors */
        /* PLLI2S_VCO = f(VCO clock) = f(PLLI2S clock input) * (PLLI2SN/PLLM) */
        /* I2SCLK = f(PLLI2S clock output) = f(VCO clock) / PLLI2SR */
        __HAL_RCC_PLLI2S_CONFIG(PeriphClkInit->PLLI2S.PLLI2SN, PeriphClkInit->PLLI2S.PLLI2SR);
#        endif /* STM32F411xE */

        /* Enable the PLLI2S */
        __HAL_RCC_PLLI2S_ENABLE();
        /* Get tick */
        tickstart = HAL_GetTick();
        /* Wait till PLLI2S is ready */
        while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLI2SRDY) == RESET) {
            if ((HAL_GetTick() - tickstart) > PLLI2S_TIMEOUT_VALUE) {
                /* return in case of Timeout detected */
                return HAL_TIMEOUT;
            }
        }
    }

    /*---------------------------- RTC configuration ---------------------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_RTC) == (RCC_PERIPHCLK_RTC)) {
        /* Check for RTC Parameters used to output RTCCLK */
        assert_param(IS_RCC_RTCCLKSOURCE(PeriphClkInit->RTCClockSelection));

        /* Enable Power Clock*/
        __HAL_RCC_PWR_CLK_ENABLE();

        /* Enable write access to Backup domain */
        PWR->CR |= PWR_CR_DBP;

        /* Get tick */
        tickstart = HAL_GetTick();

        while ((PWR->CR & PWR_CR_DBP) == RESET) {
            if ((HAL_GetTick() - tickstart) > RCC_DBP_TIMEOUT_VALUE) {
                return HAL_TIMEOUT;
            }
        }
        /* Reset the Backup domain only if the RTC Clock source selection is modified from reset value */
        tmpreg1 = (RCC->BDCR & RCC_BDCR_RTCSEL);
        if ((tmpreg1 != 0x00000000U) && ((tmpreg1) != (PeriphClkInit->RTCClockSelection & RCC_BDCR_RTCSEL))) {
            /* Store the content of BDCR register before the reset of Backup Domain */
            tmpreg1 = (RCC->BDCR & ~(RCC_BDCR_RTCSEL));
            /* RTC Clock selection can be changed only if the Backup Domain is reset */
            __HAL_RCC_BACKUPRESET_FORCE();
            __HAL_RCC_BACKUPRESET_RELEASE();
            /* Restore the Content of BDCR register */
            RCC->BDCR = tmpreg1;

            /* Wait for LSE reactivation if LSE was enable prior to Backup Domain reset */
            if (HAL_IS_BIT_SET(RCC->BDCR, RCC_BDCR_LSEON)) {
                /* Get tick */
                tickstart = HAL_GetTick();

                /* Wait till LSE is ready */
                while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) == RESET) {
                    if ((HAL_GetTick() - tickstart) > RCC_LSE_TIMEOUT_VALUE) {
                        return HAL_TIMEOUT;
                    }
                }
            }
        }
        __HAL_RCC_RTC_CONFIG(PeriphClkInit->RTCClockSelection);
    }
#        if defined(STM32F401xC) || defined(STM32F401xE) || defined(STM32F411xE)
    /*---------------------------- TIM configuration ---------------------------*/
    if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_TIM) == (RCC_PERIPHCLK_TIM)) {
        __HAL_RCC_TIMCLKPRESCALER(PeriphClkInit->TIMPresSelection);
    }
#        endif /* STM32F401xC || STM32F401xE || STM32F411xE */
    return HAL_OK;
}

/**
 * @brief  Configures the RCC_OscInitStruct according to the internal
 * RCC configuration registers.
 * @param  PeriphClkInit pointer to an RCC_PeriphCLKInitTypeDef structure that
 * will be configured.
 * @retval None
 */
void HAL_RCCEx_GetPeriphCLKConfig(RCC_PeriphCLKInitTypeDef* PeriphClkInit)
{
    uint32_t tempreg;

    /* Set all possible values for the extended clock type parameter------------*/
    PeriphClkInit->PeriphClockSelection = RCC_PERIPHCLK_I2S | RCC_PERIPHCLK_RTC;

    /* Get the PLLI2S Clock configuration --------------------------------------*/
    PeriphClkInit->PLLI2S.PLLI2SN =
        (uint32_t)((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SN) >> RCC_PLLI2SCFGR_PLLI2SN_Pos);
    PeriphClkInit->PLLI2S.PLLI2SR =
        (uint32_t)((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SR) >> RCC_PLLI2SCFGR_PLLI2SR_Pos);
#        if defined(STM32F411xE)
    PeriphClkInit->PLLI2S.PLLI2SM = (uint32_t)(RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SM);
#        endif /* STM32F411xE */
    /* Get the RTC Clock configuration -----------------------------------------*/
    tempreg = (RCC->CFGR & RCC_CFGR_RTCPRE);
    PeriphClkInit->RTCClockSelection = (uint32_t)((tempreg) | (RCC->BDCR & RCC_BDCR_RTCSEL));

#        if defined(STM32F401xC) || defined(STM32F401xE) || defined(STM32F411xE)
    /* Get the TIM Prescaler configuration -------------------------------------*/
    if ((RCC->DCKCFGR & RCC_DCKCFGR_TIMPRE) == RESET) {
        PeriphClkInit->TIMPresSelection = RCC_TIMPRES_DESACTIVATED;
    }
    else {
        PeriphClkInit->TIMPresSelection = RCC_TIMPRES_ACTIVATED;
    }
#        endif /* STM32F401xC || STM32F401xE || STM32F411xE */
}

/**
 * @brief  Return the peripheral clock frequency for a given peripheral(SAI..)
 * @note   Return 0 if peripheral clock identifier not managed by this API
 * @param  PeriphClk Peripheral clock identifier
 *         This parameter can be one of the following values:
 *            @arg RCC_PERIPHCLK_I2S: I2S peripheral clock
 * @retval Frequency in KHz
 */
uint32_t HAL_RCCEx_GetPeriphCLKFreq(uint32_t PeriphClk)
{
    /* This variable used to store the I2S clock frequency (value in Hz) */
    uint32_t frequency = 0U;
    /* This variable used to store the VCO Input (value in Hz) */
    uint32_t vcoinput = 0U;
    uint32_t srcclk = 0U;
    /* This variable used to store the VCO Output (value in Hz) */
    uint32_t vcooutput = 0U;
    switch (PeriphClk) {
        case RCC_PERIPHCLK_I2S: {
            /* Get the current I2S source */
            srcclk = __HAL_RCC_GET_I2S_SOURCE();
            switch (srcclk) {
                /* Check if I2S clock selection is External clock mapped on the I2S_CKIN pin used as I2S clock */
                case RCC_I2SCLKSOURCE_EXT: {
                    /* Set the I2S clock to the external clock  value */
                    frequency = EXTERNAL_CLOCK_VALUE;
                    break;
                }
                /* Check if I2S clock selection is PLLI2S VCO output clock divided by PLLI2SR used as I2S clock */
                case RCC_I2SCLKSOURCE_PLLI2S: {
#        if defined(STM32F411xE)
                    /* Configure the PLLI2S division factor */
                    /* PLLI2S_VCO Input  = PLL_SOURCE/PLLI2SM */
                    if ((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLSOURCE_HSE) {
                        /* Get the I2S source clock value */
                        vcoinput = (uint32_t)(HSE_VALUE / (uint32_t)(RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SM));
                    }
                    else {
                        /* Get the I2S source clock value */
                        vcoinput = (uint32_t)(HSI_VALUE / (uint32_t)(RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SM));
                    }
#        else
                    /* Configure the PLLI2S division factor */
                    /* PLLI2S_VCO Input  = PLL_SOURCE/PLLM */
                    if ((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLSOURCE_HSE) {
                        /* Get the I2S source clock value */
                        vcoinput = (uint32_t)(HSE_VALUE / (uint32_t)(RCC->PLLCFGR & RCC_PLLCFGR_PLLM));
                    }
                    else {
                        /* Get the I2S source clock value */
                        vcoinput = (uint32_t)(HSI_VALUE / (uint32_t)(RCC->PLLCFGR & RCC_PLLCFGR_PLLM));
                    }
#        endif /* STM32F411xE */
                    /* PLLI2S_VCO Output = PLLI2S_VCO Input * PLLI2SN */
                    vcooutput = (uint32_t)(
                        vcoinput
                        * (((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SN) >> 6U) & (RCC_PLLI2SCFGR_PLLI2SN >> 6U)));
                    /* I2S_CLK = PLLI2S_VCO Output/PLLI2SR */
                    frequency = (uint32_t)(
                        vcooutput
                        / (((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SR) >> 28U) & (RCC_PLLI2SCFGR_PLLI2SR >> 28U)));
                    break;
                }
                    /* Clock not enabled for I2S*/
                default: {
                    frequency = 0U;
                    break;
                }
            }
            break;
        }
    }
    return frequency;
}
#    endif /* STM32F405xx || STM32F415xx || STM32F407xx || STM32F417xx || STM32F401xC || STM32F401xE  || STM32F411xE \
            */

#    if defined(STM32F410Tx) || defined(STM32F410Cx) || defined(STM32F410Rx) || defined(STM32F411xE)    \
        || defined(STM32F446xx) || defined(STM32F469xx) || defined(STM32F479xx) || defined(STM32F412Zx) \
        || defined(STM32F412Vx) || defined(STM32F412Rx) || defined(STM32F412Cx) || defined(STM32F413xx) \
        || defined(STM32F423xx)
/**
 * @brief  Select LSE mode
 *
 * @note   This mode is only available for
 * STM32F410xx/STM32F411xx/STM32F446xx/STM32F469xx/STM32F479xx/STM32F412Zx/STM32F412Vx/STM32F412Rx/STM32F412Cx  devices.
 *
 * @param  Mode specifies the LSE mode.
 *          This parameter can be one of the following values:
 *            @arg RCC_LSE_LOWPOWER_MODE:  LSE oscillator in low power mode selection
 *            @arg RCC_LSE_HIGHDRIVE_MODE: LSE oscillator in High Drive mode selection
 * @retval None
 */
void HAL_RCCEx_SelectLSEMode(uint8_t Mode)
{
    /* Check the parameters */
    assert_param(IS_RCC_LSE_MODE(Mode));
    if (Mode == RCC_LSE_HIGHDRIVE_MODE) {
        SET_BIT(RCC->BDCR, RCC_BDCR_LSEMOD);
    }
    else {
        CLEAR_BIT(RCC->BDCR, RCC_BDCR_LSEMOD);
    }
}

#    endif /* STM32F410xx || STM32F411xE || STM32F446xx || STM32F469xx || STM32F479xx || STM32F412Zx || STM32F412Vx || \
              STM32F412Rx || STM32F412Cx || STM32F413xx || STM32F423xx */

/** @defgroup RCCEx_Exported_Functions_Group2 Extended Clock management functions
 *  @brief  Extended Clock management functions
 *
@verbatim
 ===============================================================================
                ##### Extended clock management functions  #####
 ===============================================================================
    [..]
    This subsection provides a set of functions allowing to control the
    activation or deactivation of PLLI2S, PLLSAI.
@endverbatim
  * @{
  */

#    if defined(RCC_PLLI2S_SUPPORT)
/**
 * @brief  Enable PLLI2S.
 * @param  PLLI2SInit  pointer to an RCC_PLLI2SInitTypeDef structure that
 *         contains the configuration information for the PLLI2S
 * @retval HAL status
 */
HAL_StatusTypeDef HAL_RCCEx_EnablePLLI2S(RCC_PLLI2SInitTypeDef* PLLI2SInit)
{
    uint32_t tickstart;

    /* Check for parameters */
    assert_param(IS_RCC_PLLI2SN_VALUE(PLLI2SInit->PLLI2SN));
    assert_param(IS_RCC_PLLI2SR_VALUE(PLLI2SInit->PLLI2SR));
#        if defined(RCC_PLLI2SCFGR_PLLI2SM)
    assert_param(IS_RCC_PLLI2SM_VALUE(PLLI2SInit->PLLI2SM));
#        endif /* RCC_PLLI2SCFGR_PLLI2SM */
#        if defined(RCC_PLLI2SCFGR_PLLI2SP)
    assert_param(IS_RCC_PLLI2SP_VALUE(PLLI2SInit->PLLI2SP));
#        endif /* RCC_PLLI2SCFGR_PLLI2SP */
#        if defined(RCC_PLLI2SCFGR_PLLI2SQ)
    assert_param(IS_RCC_PLLI2SQ_VALUE(PLLI2SInit->PLLI2SQ));
#        endif /* RCC_PLLI2SCFGR_PLLI2SQ */

    /* Disable the PLLI2S */
    __HAL_RCC_PLLI2S_DISABLE();

    /* Wait till PLLI2S is disabled */
    tickstart = HAL_GetTick();
    while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLI2SRDY) != RESET) {
        if ((HAL_GetTick() - tickstart) > PLLI2S_TIMEOUT_VALUE) {
            /* return in case of Timeout detected */
            return HAL_TIMEOUT;
        }
    }

    /* Configure the PLLI2S division factors */
#        if defined(STM32F446xx)
    /* PLLI2S_VCO = f(VCO clock) = f(PLLI2S clock input) * (PLLI2SN/PLLI2SM) */
    /* I2SPCLK = PLLI2S_VCO / PLLI2SP */
    /* I2SQCLK = PLLI2S_VCO / PLLI2SQ */
    /* I2SRCLK = PLLI2S_VCO / PLLI2SR */
    __HAL_RCC_PLLI2S_CONFIG(
        PLLI2SInit->PLLI2SM, PLLI2SInit->PLLI2SN, PLLI2SInit->PLLI2SP, PLLI2SInit->PLLI2SQ, PLLI2SInit->PLLI2SR);
#        elif defined(STM32F412Zx) || defined(STM32F412Vx) || defined(STM32F412Rx) || defined(STM32F412Cx) \
            || defined(STM32F413xx) || defined(STM32F423xx)
    /* PLLI2S_VCO = f(VCO clock) = f(PLLI2S clock input) * (PLLI2SN/PLLI2SM)*/
    /* I2SQCLK = PLLI2S_VCO / PLLI2SQ */
    /* I2SRCLK = PLLI2S_VCO / PLLI2SR */
    __HAL_RCC_PLLI2S_CONFIG(PLLI2SInit->PLLI2SM, PLLI2SInit->PLLI2SN, PLLI2SInit->PLLI2SQ, PLLI2SInit->PLLI2SR);
#        elif defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx) \
            || defined(STM32F469xx) || defined(STM32F479xx)
    /* PLLI2S_VCO = f(VCO clock) = f(PLLI2S clock input) * PLLI2SN */
    /* I2SQCLK = PLLI2S_VCO / PLLI2SQ */
    /* I2SRCLK = PLLI2S_VCO / PLLI2SR */
    __HAL_RCC_PLLI2S_SAICLK_CONFIG(PLLI2SInit->PLLI2SN, PLLI2SInit->PLLI2SQ, PLLI2SInit->PLLI2SR);
#        elif defined(STM32F411xE)
    /* PLLI2S_VCO = f(VCO clock) = f(PLLI2S clock input) * (PLLI2SN/PLLI2SM) */
    /* I2SRCLK = PLLI2S_VCO / PLLI2SR */
    __HAL_RCC_PLLI2S_I2SCLK_CONFIG(PLLI2SInit->PLLI2SM, PLLI2SInit->PLLI2SN, PLLI2SInit->PLLI2SR);
#        else
    /* PLLI2S_VCO = f(VCO clock) = f(PLLI2S clock input) x PLLI2SN */
    /* I2SRCLK = PLLI2S_VCO / PLLI2SR */
    __HAL_RCC_PLLI2S_CONFIG(PLLI2SInit->PLLI2SN, PLLI2SInit->PLLI2SR);
#        endif /* STM32F446xx */

    /* Enable the PLLI2S */
    __HAL_RCC_PLLI2S_ENABLE();

    /* Wait till PLLI2S is ready */
    tickstart = HAL_GetTick();
    while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLI2SRDY) == RESET) {
        if ((HAL_GetTick() - tickstart) > PLLI2S_TIMEOUT_VALUE) {
            /* return in case of Timeout detected */
            return HAL_TIMEOUT;
        }
    }

    return HAL_OK;
}

/**
 * @brief  Disable PLLI2S.
 * @retval HAL status
 */
HAL_StatusTypeDef HAL_RCCEx_DisablePLLI2S(void)
{
    uint32_t tickstart;

    /* Disable the PLLI2S */
    __HAL_RCC_PLLI2S_DISABLE();

    /* Wait till PLLI2S is disabled */
    tickstart = HAL_GetTick();
    while (READ_BIT(RCC->CR, RCC_CR_PLLI2SRDY) != RESET) {
        if ((HAL_GetTick() - tickstart) > PLLI2S_TIMEOUT_VALUE) {
            /* return in case of Timeout detected */
            return HAL_TIMEOUT;
        }
    }

    return HAL_OK;
}

#    endif /* RCC_PLLI2S_SUPPORT */

#    if defined(RCC_PLLSAI_SUPPORT)
/**
 * @brief  Enable PLLSAI.
 * @param  PLLSAIInit  pointer to an RCC_PLLSAIInitTypeDef structure that
 *         contains the configuration information for the PLLSAI
 * @retval HAL status
 */
HAL_StatusTypeDef HAL_RCCEx_EnablePLLSAI(RCC_PLLSAIInitTypeDef* PLLSAIInit)
{
    uint32_t tickstart;

    /* Check for parameters */
    assert_param(IS_RCC_PLLSAIN_VALUE(PLLSAIInit->PLLSAIN));
    assert_param(IS_RCC_PLLSAIQ_VALUE(PLLSAIInit->PLLSAIQ));
#        if defined(RCC_PLLSAICFGR_PLLSAIM)
    assert_param(IS_RCC_PLLSAIM_VALUE(PLLSAIInit->PLLSAIM));
#        endif /* RCC_PLLSAICFGR_PLLSAIM */
#        if defined(RCC_PLLSAICFGR_PLLSAIP)
    assert_param(IS_RCC_PLLSAIP_VALUE(PLLSAIInit->PLLSAIP));
#        endif /* RCC_PLLSAICFGR_PLLSAIP */
#        if defined(RCC_PLLSAICFGR_PLLSAIR)
    assert_param(IS_RCC_PLLSAIR_VALUE(PLLSAIInit->PLLSAIR));
#        endif /* RCC_PLLSAICFGR_PLLSAIR */

    /* Disable the PLLSAI */
    __HAL_RCC_PLLSAI_DISABLE();

    /* Wait till PLLSAI is disabled */
    tickstart = HAL_GetTick();
    while (__HAL_RCC_PLLSAI_GET_FLAG() != RESET) {
        if ((HAL_GetTick() - tickstart) > PLLSAI_TIMEOUT_VALUE) {
            /* return in case of Timeout detected */
            return HAL_TIMEOUT;
        }
    }

    /* Configure the PLLSAI division factors */
#        if defined(STM32F446xx)
    /* PLLSAI_VCO = f(VCO clock) = f(PLLSAI clock input) * (PLLSAIN/PLLSAIM) */
    /* SAIPCLK = PLLSAI_VCO / PLLSAIP */
    /* SAIQCLK = PLLSAI_VCO / PLLSAIQ */
    /* SAIRCLK = PLLSAI_VCO / PLLSAIR */
    __HAL_RCC_PLLSAI_CONFIG(PLLSAIInit->PLLSAIM, PLLSAIInit->PLLSAIN, PLLSAIInit->PLLSAIP, PLLSAIInit->PLLSAIQ, 0U);
#        elif defined(STM32F469xx) || defined(STM32F479xx)
    /* PLLSAI_VCO = f(VCO clock) = f(PLLSAI clock input) * PLLSAIN */
    /* SAIPCLK = PLLSAI_VCO / PLLSAIP */
    /* SAIQCLK = PLLSAI_VCO / PLLSAIQ */
    /* SAIRCLK = PLLSAI_VCO / PLLSAIR */
    __HAL_RCC_PLLSAI_CONFIG(PLLSAIInit->PLLSAIN, PLLSAIInit->PLLSAIP, PLLSAIInit->PLLSAIQ, PLLSAIInit->PLLSAIR);
#        else
    /* PLLSAI_VCO = f(VCO clock) = f(PLLSAI clock input) x PLLSAIN */
    /* SAIQCLK = PLLSAI_VCO / PLLSAIQ */
    /* SAIRCLK = PLLSAI_VCO / PLLSAIR */
    __HAL_RCC_PLLSAI_CONFIG(PLLSAIInit->PLLSAIN, PLLSAIInit->PLLSAIQ, PLLSAIInit->PLLSAIR);
#        endif /* STM32F446xx */

    /* Enable the PLLSAI */
    __HAL_RCC_PLLSAI_ENABLE();

    /* Wait till PLLSAI is ready */
    tickstart = HAL_GetTick();
    while (__HAL_RCC_PLLSAI_GET_FLAG() == RESET) {
        if ((HAL_GetTick() - tickstart) > PLLSAI_TIMEOUT_VALUE) {
            /* return in case of Timeout detected */
            return HAL_TIMEOUT;
        }
    }

    return HAL_OK;
}

/**
 * @brief  Disable PLLSAI.
 * @retval HAL status
 */
HAL_StatusTypeDef HAL_RCCEx_DisablePLLSAI(void)
{
    uint32_t tickstart;

    /* Disable the PLLSAI */
    __HAL_RCC_PLLSAI_DISABLE();

    /* Wait till PLLSAI is disabled */
    tickstart = HAL_GetTick();
    while (__HAL_RCC_PLLSAI_GET_FLAG() != RESET) {
        if ((HAL_GetTick() - tickstart) > PLLSAI_TIMEOUT_VALUE) {
            /* return in case of Timeout detected */
            return HAL_TIMEOUT;
        }
    }

    return HAL_OK;
}

#    endif /* RCC_PLLSAI_SUPPORT */

/**
 * @}
 */

#    if defined(STM32F446xx)
/**
 * @brief  Returns the SYSCLK frequency
 *
 * @note   This function implementation is valid only for STM32F446xx devices.
 * @note   This function add the PLL/PLLR System clock source
 *
 * @note   The system frequency computed by this function is not the real
 *         frequency in the chip. It is calculated based on the predefined
 *         constant and the selected clock source:
 * @note     If SYSCLK source is HSI, function returns values based on HSI_VALUE(*)
 * @note     If SYSCLK source is HSE, function returns values based on HSE_VALUE(**)
 * @note     If SYSCLK source is PLL or PLLR, function returns values based on HSE_VALUE(**)
 *           or HSI_VALUE(*) multiplied/divided by the PLL factors.
 * @note     (*) HSI_VALUE is a constant defined in stm32f4xx_hal_conf.h file (default value
 *               16 MHz) but the real value may vary depending on the variations
 *               in voltage and temperature.
 * @note     (**) HSE_VALUE is a constant defined in stm32f4xx_hal_conf.h file (default value
 *                25 MHz), user has to ensure that HSE_VALUE is same as the real
 *                frequency of the crystal used. Otherwise, this function may
 *                have wrong result.
 *
 * @note   The result of this function could be not correct when using fractional
 *         value for HSE crystal.
 *
 * @note   This function can be used by the user application to compute the
 *         baudrate for the communication peripherals or configure other parameters.
 *
 * @note   Each time SYSCLK changes, this function must be called to update the
 *         right SYSCLK value. Otherwise, any configuration based on this function will be incorrect.
 *
 *
 * @retval SYSCLK frequency
 */
uint32_t HAL_RCC_GetSysClockFreq(void)
{
    uint32_t pllm = 0U;
    uint32_t pllvco = 0U;
    uint32_t pllp = 0U;
    uint32_t pllr = 0U;
    uint32_t sysclockfreq = 0U;

    /* Get SYSCLK source -------------------------------------------------------*/
    switch (RCC->CFGR & RCC_CFGR_SWS) {
        case RCC_CFGR_SWS_HSI: /* HSI used as system clock source */
        {
            sysclockfreq = HSI_VALUE;
            break;
        }
        case RCC_CFGR_SWS_HSE: /* HSE used as system clock  source */
        {
            sysclockfreq = HSE_VALUE;
            break;
        }
        case RCC_CFGR_SWS_PLL: /* PLL/PLLP used as system clock  source */
        {
            /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLLM) * PLLN
            SYSCLK = PLL_VCO / PLLP */
            pllm = RCC->PLLCFGR & RCC_PLLCFGR_PLLM;
            if (__HAL_RCC_GET_PLL_OSCSOURCE() != RCC_PLLSOURCE_HSI) {
                /* HSE used as PLL clock source */
                pllvco = (uint32_t)(
                    (((uint64_t)HSE_VALUE * ((uint64_t)((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos))))
                    / (uint64_t)pllm);
            }
            else {
                /* HSI used as PLL clock source */
                pllvco = (uint32_t)(
                    (((uint64_t)HSI_VALUE * ((uint64_t)((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos))))
                    / (uint64_t)pllm);
            }
            pllp = ((((RCC->PLLCFGR & RCC_PLLCFGR_PLLP) >> RCC_PLLCFGR_PLLP_Pos) + 1U) * 2U);

            sysclockfreq = pllvco / pllp;
            break;
        }
        case RCC_CFGR_SWS_PLLR: /* PLL/PLLR used as system clock  source */
        {
            /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLLM) * PLLN
            SYSCLK = PLL_VCO / PLLR */
            pllm = RCC->PLLCFGR & RCC_PLLCFGR_PLLM;
            if (__HAL_RCC_GET_PLL_OSCSOURCE() != RCC_PLLSOURCE_HSI) {
                /* HSE used as PLL clock source */
                pllvco = (uint32_t)(
                    (((uint64_t)HSE_VALUE * ((uint64_t)((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos))))
                    / (uint64_t)pllm);
            }
            else {
                /* HSI used as PLL clock source */
                pllvco = (uint32_t)(
                    (((uint64_t)HSI_VALUE * ((uint64_t)((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos))))
                    / (uint64_t)pllm);
            }
            pllr = ((RCC->PLLCFGR & RCC_PLLCFGR_PLLR) >> RCC_PLLCFGR_PLLR_Pos);

            sysclockfreq = pllvco / pllr;
            break;
        }
        default: {
            sysclockfreq = HSI_VALUE;
            break;
        }
    }
    return sysclockfreq;
}
#    endif /* STM32F446xx */

/**
 * @}
 */

/**
 * @}
 */

/**
 * @brief  Resets the RCC clock configuration to the default reset state.
 * @note   The default reset state of the clock configuration is given below:
 *            - HSI ON and used as system clock source
 *            - HSE, PLL, PLLI2S and PLLSAI OFF
 *            - AHB, APB1 and APB2 prescaler set to 1.
 *            - CSS, MCO1 and MCO2 OFF
 *            - All interrupts disabled
 * @note   This function doesn't modify the configuration of the
 *            - Peripheral clocks
 *            - LSI, LSE and RTC clocks
 * @retval HAL status
 */
HAL_StatusTypeDef HAL_RCC_DeInit(void)
{
    uint32_t tickstart;

    /* Get Start Tick */
    tickstart = HAL_GetTick();

    /* Set HSION bit to the reset value */
    SET_BIT(RCC->CR, RCC_CR_HSION);

    /* Wait till HSI is ready */
    while (READ_BIT(RCC->CR, RCC_CR_HSIRDY) == RESET) {
        if ((HAL_GetTick() - tickstart) > HSI_TIMEOUT_VALUE) {
            return HAL_TIMEOUT;
        }
    }

    /* Set HSITRIM[4:0] bits to the reset value */
    SET_BIT(RCC->CR, RCC_CR_HSITRIM_4);

    /* Get Start Tick */
    tickstart = HAL_GetTick();

    /* Reset CFGR register */
    CLEAR_REG(RCC->CFGR);

    /* Wait till clock switch is ready */
    while (READ_BIT(RCC->CFGR, RCC_CFGR_SWS) != RESET) {
        if ((HAL_GetTick() - tickstart) > CLOCKSWITCH_TIMEOUT_VALUE) {
            return HAL_TIMEOUT;
        }
    }

    /* Get Start Tick */
    tickstart = HAL_GetTick();

    /* Clear HSEON, HSEBYP and CSSON bits */
    CLEAR_BIT(RCC->CR, RCC_CR_HSEON | RCC_CR_HSEBYP | RCC_CR_CSSON);

    /* Wait till HSE is disabled */
    while (READ_BIT(RCC->CR, RCC_CR_HSERDY) != RESET) {
        if ((HAL_GetTick() - tickstart) > HSE_TIMEOUT_VALUE) {
            return HAL_TIMEOUT;
        }
    }

    /* Get Start Tick */
    tickstart = HAL_GetTick();

    /* Clear PLLON bit */
    CLEAR_BIT(RCC->CR, RCC_CR_PLLON);

    /* Wait till PLL is disabled */
    while (READ_BIT(RCC->CR, RCC_CR_PLLRDY) != RESET) {
        if ((HAL_GetTick() - tickstart) > PLL_TIMEOUT_VALUE) {
            return HAL_TIMEOUT;
        }
    }

#    if defined(RCC_PLLI2S_SUPPORT)
    /* Get Start Tick */
    tickstart = HAL_GetTick();

    /* Reset PLLI2SON bit */
    CLEAR_BIT(RCC->CR, RCC_CR_PLLI2SON);

    /* Wait till PLLI2S is disabled */
    while (READ_BIT(RCC->CR, RCC_CR_PLLI2SRDY) != RESET) {
        if ((HAL_GetTick() - tickstart) > PLLI2S_TIMEOUT_VALUE) {
            return HAL_TIMEOUT;
        }
    }
#    endif /* RCC_PLLI2S_SUPPORT */

#    if defined(RCC_PLLSAI_SUPPORT)
    /* Get Start Tick */
    tickstart = HAL_GetTick();

    /* Reset PLLSAI bit */
    CLEAR_BIT(RCC->CR, RCC_CR_PLLSAION);

    /* Wait till PLLSAI is disabled */
    while (READ_BIT(RCC->CR, RCC_CR_PLLSAIRDY) != RESET) {
        if ((HAL_GetTick() - tickstart) > PLLSAI_TIMEOUT_VALUE) {
            return HAL_TIMEOUT;
        }
    }
#    endif /* RCC_PLLSAI_SUPPORT */

    /* Once PLL, PLLI2S and PLLSAI are OFF, reset PLLCFGR register to default value */
#    if defined(STM32F412Cx) || defined(STM32F412Rx) || defined(STM32F412Vx) || defined(STM32F412Zx)    \
        || defined(STM32F413xx) || defined(STM32F423xx) || defined(STM32F446xx) || defined(STM32F469xx) \
        || defined(STM32F479xx)
    RCC->PLLCFGR =
        RCC_PLLCFGR_PLLM_4 | RCC_PLLCFGR_PLLN_6 | RCC_PLLCFGR_PLLN_7 | RCC_PLLCFGR_PLLQ_2 | RCC_PLLCFGR_PLLR_1;
#    elif defined(STM32F410Tx) || defined(STM32F410Cx) || defined(STM32F410Rx)
    RCC->PLLCFGR = RCC_PLLCFGR_PLLR_0 | RCC_PLLCFGR_PLLR_1 | RCC_PLLCFGR_PLLR_2 | RCC_PLLCFGR_PLLM_4
                   | RCC_PLLCFGR_PLLN_6 | RCC_PLLCFGR_PLLN_7 | RCC_PLLCFGR_PLLQ_0 | RCC_PLLCFGR_PLLQ_1
                   | RCC_PLLCFGR_PLLQ_2 | RCC_PLLCFGR_PLLQ_3;
#    else
    RCC->PLLCFGR = RCC_PLLCFGR_PLLM_4 | RCC_PLLCFGR_PLLN_6 | RCC_PLLCFGR_PLLN_7 | RCC_PLLCFGR_PLLQ_2;
#    endif /* STM32F412Cx || STM32F412Rx || STM32F412Vx || STM32F412Zx || STM32F413xx || STM32F423xx || STM32F446xx || \
              STM32F469xx || STM32F479xx */

    /* Reset PLLI2SCFGR register to default value */
#    if defined(STM32F412Cx) || defined(STM32F412Rx) || defined(STM32F412Vx) || defined(STM32F412Zx) \
        || defined(STM32F413xx) || defined(STM32F423xx) || defined(STM32F446xx)
    RCC->PLLI2SCFGR = RCC_PLLI2SCFGR_PLLI2SM_4 | RCC_PLLI2SCFGR_PLLI2SN_6 | RCC_PLLI2SCFGR_PLLI2SN_7
                      | RCC_PLLI2SCFGR_PLLI2SQ_2 | RCC_PLLI2SCFGR_PLLI2SR_1;
#    elif defined(STM32F401xC) || defined(STM32F401xE) || defined(STM32F405xx) || defined(STM32F415xx) \
        || defined(STM32F407xx) || defined(STM32F417xx)
    RCC->PLLI2SCFGR = RCC_PLLI2SCFGR_PLLI2SN_6 | RCC_PLLI2SCFGR_PLLI2SN_7 | RCC_PLLI2SCFGR_PLLI2SR_1;
#    elif defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx) \
        || defined(STM32F469xx) || defined(STM32F479xx)
    RCC->PLLI2SCFGR =
        RCC_PLLI2SCFGR_PLLI2SN_6 | RCC_PLLI2SCFGR_PLLI2SN_7 | RCC_PLLI2SCFGR_PLLI2SQ_2 | RCC_PLLI2SCFGR_PLLI2SR_1;
#    elif defined(STM32F411xE)
    RCC->PLLI2SCFGR =
        RCC_PLLI2SCFGR_PLLI2SM_4 | RCC_PLLI2SCFGR_PLLI2SN_6 | RCC_PLLI2SCFGR_PLLI2SN_7 | RCC_PLLI2SCFGR_PLLI2SR_1;
#    endif /* STM32F412Cx || STM32F412Rx || STM32F412Vx || STM32F412Zx || STM32F413xx || STM32F423xx || STM32F446xx */

    /* Reset PLLSAICFGR register */
#    if defined(STM32F427xx) || defined(STM32F429xx) || defined(STM32F437xx) || defined(STM32F439xx) \
        || defined(STM32F469xx) || defined(STM32F479xx)
    RCC->PLLSAICFGR =
        RCC_PLLSAICFGR_PLLSAIN_6 | RCC_PLLSAICFGR_PLLSAIN_7 | RCC_PLLSAICFGR_PLLSAIQ_2 | RCC_PLLSAICFGR_PLLSAIR_1;
#    elif defined(STM32F446xx)
    RCC->PLLSAICFGR =
        RCC_PLLSAICFGR_PLLSAIM_4 | RCC_PLLSAICFGR_PLLSAIN_6 | RCC_PLLSAICFGR_PLLSAIN_7 | RCC_PLLSAICFGR_PLLSAIQ_2;
#    endif /* STM32F427xx || STM32F429xx || STM32F437xx || STM32F439xx || STM32F469xx || STM32F479xx */

    /* Disable all interrupts */
    CLEAR_BIT(RCC->CIR, RCC_CIR_LSIRDYIE | RCC_CIR_LSERDYIE | RCC_CIR_HSIRDYIE | RCC_CIR_HSERDYIE | RCC_CIR_PLLRDYIE);

#    if defined(RCC_CIR_PLLI2SRDYIE)
    CLEAR_BIT(RCC->CIR, RCC_CIR_PLLI2SRDYIE);
#    endif /* RCC_CIR_PLLI2SRDYIE */

#    if defined(RCC_CIR_PLLSAIRDYIE)
    CLEAR_BIT(RCC->CIR, RCC_CIR_PLLSAIRDYIE);
#    endif /* RCC_CIR_PLLSAIRDYIE */

    /* Clear all interrupt flags */
    SET_BIT(RCC->CIR,
            RCC_CIR_LSIRDYC | RCC_CIR_LSERDYC | RCC_CIR_HSIRDYC | RCC_CIR_HSERDYC | RCC_CIR_PLLRDYC | RCC_CIR_CSSC);

#    if defined(RCC_CIR_PLLI2SRDYC)
    SET_BIT(RCC->CIR, RCC_CIR_PLLI2SRDYC);
#    endif /* RCC_CIR_PLLI2SRDYC */

#    if defined(RCC_CIR_PLLSAIRDYC)
    SET_BIT(RCC->CIR, RCC_CIR_PLLSAIRDYC);
#    endif /* RCC_CIR_PLLSAIRDYC */

    /* Clear LSION bit */
    CLEAR_BIT(RCC->CSR, RCC_CSR_LSION);

    /* Reset all CSR flags */
    SET_BIT(RCC->CSR, RCC_CSR_RMVF);

    /* Update the SystemCoreClock global variable */
    SystemCoreClock = HSI_VALUE;

    /* Adapt Systick interrupt period */
    if (HAL_InitTick(uwTickPrio) != HAL_OK) {
        return HAL_ERROR;
    }
    else {
        return HAL_OK;
    }
}

#    if defined(STM32F410Tx) || defined(STM32F410Cx) || defined(STM32F410Rx) || defined(STM32F446xx)    \
        || defined(STM32F469xx) || defined(STM32F479xx) || defined(STM32F412Zx) || defined(STM32F412Vx) \
        || defined(STM32F412Rx) || defined(STM32F412Cx) || defined(STM32F413xx) || defined(STM32F423xx)
/**
 * @brief  Initializes the RCC Oscillators according to the specified parameters in the
 *         RCC_OscInitTypeDef.
 * @param  RCC_OscInitStruct pointer to an RCC_OscInitTypeDef structure that
 *         contains the configuration information for the RCC Oscillators.
 * @note   The PLL is not disabled when used as system clock.
 * @note   Transitions LSE Bypass to LSE On and LSE On to LSE Bypass are not
 *         supported by this API. User should request a transition to LSE Off
 *         first and then LSE On or LSE Bypass.
 * @note   Transition HSE Bypass to HSE On and HSE On to HSE Bypass are not
 *         supported by this API. User should request a transition to HSE Off
 *         first and then HSE On or HSE Bypass.
 * @note   This function add the PLL/PLLR factor management during PLL configuration this feature
 *         is only available in
 * STM32F410xx/STM32F446xx/STM32F469xx/STM32F479xx/STM32F412Zx/STM32F412Vx/STM32F412Rx/STM32F412Cx devices
 * @retval HAL status
 */
HAL_StatusTypeDef HAL_RCC_OscConfig(RCC_OscInitTypeDef* RCC_OscInitStruct)
{
    uint32_t tickstart, pll_config;

    /* Check Null pointer */
    if (RCC_OscInitStruct == NULL) {
        return HAL_ERROR;
    }

    /* Check the parameters */
    assert_param(IS_RCC_OSCILLATORTYPE(RCC_OscInitStruct->OscillatorType));
    /*------------------------------- HSE Configuration ------------------------*/
    if (((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_HSE) == RCC_OSCILLATORTYPE_HSE) {
        /* Check the parameters */
        assert_param(IS_RCC_HSE(RCC_OscInitStruct->HSEState));
        /* When the HSE is used as system clock or clock source for PLL in these cases HSE will not disabled */
#        if defined(STM32F446xx)
        if ((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_CFGR_SWS_HSE)
            || ((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_CFGR_SWS_PLL)
                && ((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLCFGR_PLLSRC_HSE))
            || ((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_CFGR_SWS_PLLR)
                && ((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLCFGR_PLLSRC_HSE)))
#        else
        if ((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_CFGR_SWS_HSE)
            || ((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_CFGR_SWS_PLL)
                && ((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLCFGR_PLLSRC_HSE)))
#        endif /* STM32F446xx */
        {
            if ((__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) != RESET) && (RCC_OscInitStruct->HSEState == RCC_HSE_OFF)) {
                return HAL_ERROR;
            }
        }
        else {
            /* Set the new HSE configuration ---------------------------------------*/
            __HAL_RCC_HSE_CONFIG(RCC_OscInitStruct->HSEState);

            /* Check the HSE State */
            if ((RCC_OscInitStruct->HSEState) != RCC_HSE_OFF) {
                /* Get Start Tick*/
                tickstart = HAL_GetTick();

                /* Wait till HSE is ready */
                while (__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) == RESET) {
                    if ((HAL_GetTick() - tickstart) > HSE_TIMEOUT_VALUE) {
                        return HAL_TIMEOUT;
                    }
                }
            }
            else {
                /* Get Start Tick*/
                tickstart = HAL_GetTick();

                /* Wait till HSE is bypassed or disabled */
                while (__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) != RESET) {
                    if ((HAL_GetTick() - tickstart) > HSE_TIMEOUT_VALUE) {
                        return HAL_TIMEOUT;
                    }
                }
            }
        }
    }
    /*----------------------------- HSI Configuration --------------------------*/
    if (((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_HSI) == RCC_OSCILLATORTYPE_HSI) {
        /* Check the parameters */
        assert_param(IS_RCC_HSI(RCC_OscInitStruct->HSIState));
        assert_param(IS_RCC_CALIBRATION_VALUE(RCC_OscInitStruct->HSICalibrationValue));

        /* Check if HSI is used as system clock or as PLL source when PLL is selected as system clock */
#        if defined(STM32F446xx)
        if ((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_CFGR_SWS_HSI)
            || ((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_CFGR_SWS_PLL)
                && ((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLCFGR_PLLSRC_HSI))
            || ((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_CFGR_SWS_PLLR)
                && ((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLCFGR_PLLSRC_HSI)))
#        else
        if ((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_CFGR_SWS_HSI)
            || ((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_CFGR_SWS_PLL)
                && ((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLCFGR_PLLSRC_HSI)))
#        endif /* STM32F446xx */
        {
            /* When HSI is used as system clock it will not disabled */
            if ((__HAL_RCC_GET_FLAG(RCC_FLAG_HSIRDY) != RESET) && (RCC_OscInitStruct->HSIState != RCC_HSI_ON)) {
                return HAL_ERROR;
            }
            /* Otherwise, just the calibration is allowed */
            else {
                /* Adjusts the Internal High Speed oscillator (HSI) calibration value.*/
                __HAL_RCC_HSI_CALIBRATIONVALUE_ADJUST(RCC_OscInitStruct->HSICalibrationValue);
            }
        }
        else {
            /* Check the HSI State */
            if ((RCC_OscInitStruct->HSIState) != RCC_HSI_OFF) {
                /* Enable the Internal High Speed oscillator (HSI). */
                __HAL_RCC_HSI_ENABLE();

                /* Get Start Tick*/
                tickstart = HAL_GetTick();

                /* Wait till HSI is ready */
                while (__HAL_RCC_GET_FLAG(RCC_FLAG_HSIRDY) == RESET) {
                    if ((HAL_GetTick() - tickstart) > HSI_TIMEOUT_VALUE) {
                        return HAL_TIMEOUT;
                    }
                }

                /* Adjusts the Internal High Speed oscillator (HSI) calibration value.*/
                __HAL_RCC_HSI_CALIBRATIONVALUE_ADJUST(RCC_OscInitStruct->HSICalibrationValue);
            }
            else {
                /* Disable the Internal High Speed oscillator (HSI). */
                __HAL_RCC_HSI_DISABLE();

                /* Get Start Tick*/
                tickstart = HAL_GetTick();

                /* Wait till HSI is ready */
                while (__HAL_RCC_GET_FLAG(RCC_FLAG_HSIRDY) != RESET) {
                    if ((HAL_GetTick() - tickstart) > HSI_TIMEOUT_VALUE) {
                        return HAL_TIMEOUT;
                    }
                }
            }
        }
    }
    /*------------------------------ LSI Configuration -------------------------*/
    if (((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_LSI) == RCC_OSCILLATORTYPE_LSI) {
        /* Check the parameters */
        assert_param(IS_RCC_LSI(RCC_OscInitStruct->LSIState));

        /* Check the LSI State */
        if ((RCC_OscInitStruct->LSIState) != RCC_LSI_OFF) {
            /* Enable the Internal Low Speed oscillator (LSI). */
            __HAL_RCC_LSI_ENABLE();

            /* Get Start Tick*/
            tickstart = HAL_GetTick();

            /* Wait till LSI is ready */
            while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSIRDY) == RESET) {
                if ((HAL_GetTick() - tickstart) > LSI_TIMEOUT_VALUE) {
                    return HAL_TIMEOUT;
                }
            }
        }
        else {
            /* Disable the Internal Low Speed oscillator (LSI). */
            __HAL_RCC_LSI_DISABLE();

            /* Get Start Tick*/
            tickstart = HAL_GetTick();

            /* Wait till LSI is ready */
            while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSIRDY) != RESET) {
                if ((HAL_GetTick() - tickstart) > LSI_TIMEOUT_VALUE) {
                    return HAL_TIMEOUT;
                }
            }
        }
    }
    /*------------------------------ LSE Configuration -------------------------*/
    if (((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_LSE) == RCC_OSCILLATORTYPE_LSE) {
        FlagStatus pwrclkchanged = RESET;

        /* Check the parameters */
        assert_param(IS_RCC_LSE(RCC_OscInitStruct->LSEState));

        /* Update LSE configuration in Backup Domain control register    */
        /* Requires to enable write access to Backup Domain of necessary */
        if (__HAL_RCC_PWR_IS_CLK_DISABLED()) {
            __HAL_RCC_PWR_CLK_ENABLE();
            pwrclkchanged = SET;
        }

        if (HAL_IS_BIT_CLR(PWR->CR, PWR_CR_DBP)) {
            /* Enable write access to Backup domain */
            SET_BIT(PWR->CR, PWR_CR_DBP);

            /* Wait for Backup domain Write protection disable */
            tickstart = HAL_GetTick();

            while (HAL_IS_BIT_CLR(PWR->CR, PWR_CR_DBP)) {
                if ((HAL_GetTick() - tickstart) > RCC_DBP_TIMEOUT_VALUE) {
                    return HAL_TIMEOUT;
                }
            }
        }

        /* Set the new LSE configuration -----------------------------------------*/
        __HAL_RCC_LSE_CONFIG(RCC_OscInitStruct->LSEState);
        /* Check the LSE State */
        if ((RCC_OscInitStruct->LSEState) != RCC_LSE_OFF) {
            /* Get Start Tick*/
            tickstart = HAL_GetTick();

            /* Wait till LSE is ready */
            while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) == RESET) {
                if ((HAL_GetTick() - tickstart) > RCC_LSE_TIMEOUT_VALUE) {
                    return HAL_TIMEOUT;
                }
            }
        }
        else {
            /* Get Start Tick*/
            tickstart = HAL_GetTick();

            /* Wait till LSE is ready */
            while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) != RESET) {
                if ((HAL_GetTick() - tickstart) > RCC_LSE_TIMEOUT_VALUE) {
                    return HAL_TIMEOUT;
                }
            }
        }

        /* Restore clock configuration if changed */
        if (pwrclkchanged == SET) {
            __HAL_RCC_PWR_CLK_DISABLE();
        }
    }
    /*-------------------------------- PLL Configuration -----------------------*/
    /* Check the parameters */
    assert_param(IS_RCC_PLL(RCC_OscInitStruct->PLL.PLLState));
    if ((RCC_OscInitStruct->PLL.PLLState) != RCC_PLL_NONE) {
        /* Check if the PLL is used as system clock or not */
        if (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_PLL) {
            if ((RCC_OscInitStruct->PLL.PLLState) == RCC_PLL_ON) {
                /* Check the parameters */
                assert_param(IS_RCC_PLLSOURCE(RCC_OscInitStruct->PLL.PLLSource));
                assert_param(IS_RCC_PLLM_VALUE(RCC_OscInitStruct->PLL.PLLM));
                assert_param(IS_RCC_PLLN_VALUE(RCC_OscInitStruct->PLL.PLLN));
                assert_param(IS_RCC_PLLP_VALUE(RCC_OscInitStruct->PLL.PLLP));
                assert_param(IS_RCC_PLLQ_VALUE(RCC_OscInitStruct->PLL.PLLQ));
                assert_param(IS_RCC_PLLR_VALUE(RCC_OscInitStruct->PLL.PLLR));

                /* Disable the main PLL. */
                __HAL_RCC_PLL_DISABLE();

                /* Get Start Tick*/
                tickstart = HAL_GetTick();

                /* Wait till PLL is ready */
                while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) != RESET) {
                    if ((HAL_GetTick() - tickstart) > PLL_TIMEOUT_VALUE) {
                        return HAL_TIMEOUT;
                    }
                }

                /* Configure the main PLL clock source, multiplication and division factors. */
                WRITE_REG(RCC->PLLCFGR,
                          (RCC_OscInitStruct->PLL.PLLSource | RCC_OscInitStruct->PLL.PLLM
                           | (RCC_OscInitStruct->PLL.PLLN << RCC_PLLCFGR_PLLN_Pos)
                           | (((RCC_OscInitStruct->PLL.PLLP >> 1U) - 1U) << RCC_PLLCFGR_PLLP_Pos)
                           | (RCC_OscInitStruct->PLL.PLLQ << RCC_PLLCFGR_PLLQ_Pos)
                           | (RCC_OscInitStruct->PLL.PLLR << RCC_PLLCFGR_PLLR_Pos)));
                /* Enable the main PLL. */
                __HAL_RCC_PLL_ENABLE();

                /* Get Start Tick*/
                tickstart = HAL_GetTick();

                /* Wait till PLL is ready */
                while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) == RESET) {
                    if ((HAL_GetTick() - tickstart) > PLL_TIMEOUT_VALUE) {
                        return HAL_TIMEOUT;
                    }
                }
            }
            else {
                /* Disable the main PLL. */
                __HAL_RCC_PLL_DISABLE();

                /* Get Start Tick*/
                tickstart = HAL_GetTick();

                /* Wait till PLL is ready */
                while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) != RESET) {
                    if ((HAL_GetTick() - tickstart) > PLL_TIMEOUT_VALUE) {
                        return HAL_TIMEOUT;
                    }
                }
            }
        }
        else {
            /* Check if there is a request to disable the PLL used as System clock source */
            if ((RCC_OscInitStruct->PLL.PLLState) == RCC_PLL_OFF) {
                return HAL_ERROR;
            }
            else {
                /* Do not return HAL_ERROR if request repeats the current configuration */
                pll_config = RCC->PLLCFGR;
#        if defined(RCC_PLLCFGR_PLLR)
                if (((RCC_OscInitStruct->PLL.PLLState) == RCC_PLL_OFF)
                    || (READ_BIT(pll_config, RCC_PLLCFGR_PLLSRC) != RCC_OscInitStruct->PLL.PLLSource)
                    || (READ_BIT(pll_config, RCC_PLLCFGR_PLLM) != (RCC_OscInitStruct->PLL.PLLM) << RCC_PLLCFGR_PLLM_Pos)
                    || (READ_BIT(pll_config, RCC_PLLCFGR_PLLN) != (RCC_OscInitStruct->PLL.PLLN) << RCC_PLLCFGR_PLLN_Pos)
                    || (READ_BIT(pll_config, RCC_PLLCFGR_PLLP)
                        != (((RCC_OscInitStruct->PLL.PLLP >> 1U) - 1U)) << RCC_PLLCFGR_PLLP_Pos)
                    || (READ_BIT(pll_config, RCC_PLLCFGR_PLLQ) != (RCC_OscInitStruct->PLL.PLLQ << RCC_PLLCFGR_PLLQ_Pos))
                    || (READ_BIT(pll_config, RCC_PLLCFGR_PLLR)
                        != (RCC_OscInitStruct->PLL.PLLR << RCC_PLLCFGR_PLLR_Pos)))
#        else
                if (((RCC_OscInitStruct->PLL.PLLState) == RCC_PLL_OFF)
                    || (READ_BIT(pll_config, RCC_PLLCFGR_PLLSRC) != RCC_OscInitStruct->PLL.PLLSource)
                    || (READ_BIT(pll_config, RCC_PLLCFGR_PLLM) != (RCC_OscInitStruct->PLL.PLLM) << RCC_PLLCFGR_PLLM_Pos)
                    || (READ_BIT(pll_config, RCC_PLLCFGR_PLLN) != (RCC_OscInitStruct->PLL.PLLN) << RCC_PLLCFGR_PLLN_Pos)
                    || (READ_BIT(pll_config, RCC_PLLCFGR_PLLP)
                        != (((RCC_OscInitStruct->PLL.PLLP >> 1U) - 1U)) << RCC_PLLCFGR_PLLP_Pos)
                    || (READ_BIT(pll_config, RCC_PLLCFGR_PLLQ)
                        != (RCC_OscInitStruct->PLL.PLLQ << RCC_PLLCFGR_PLLQ_Pos)))
#        endif
                {
                    return HAL_ERROR;
                }
            }
        }
    }
    return HAL_OK;
}

/**
 * @brief  Configures the RCC_OscInitStruct according to the internal
 * RCC configuration registers.
 * @param  RCC_OscInitStruct pointer to an RCC_OscInitTypeDef structure that will be configured.
 *
 * @note   This function is only available in case of
 * STM32F410xx/STM32F446xx/STM32F469xx/STM32F479xx/STM32F412Zx/STM32F412Vx/STM32F412Rx/STM32F412Cx devices.
 * @note   This function add the PLL/PLLR factor management
 * @retval None
 */
void HAL_RCC_GetOscConfig(RCC_OscInitTypeDef* RCC_OscInitStruct)
{
    /* Set all possible values for the Oscillator type parameter ---------------*/
    RCC_OscInitStruct->OscillatorType =
        RCC_OSCILLATORTYPE_HSE | RCC_OSCILLATORTYPE_HSI | RCC_OSCILLATORTYPE_LSE | RCC_OSCILLATORTYPE_LSI;

    /* Get the HSE configuration -----------------------------------------------*/
    if ((RCC->CR & RCC_CR_HSEBYP) == RCC_CR_HSEBYP) {
        RCC_OscInitStruct->HSEState = RCC_HSE_BYPASS;
    }
    else if ((RCC->CR & RCC_CR_HSEON) == RCC_CR_HSEON) {
        RCC_OscInitStruct->HSEState = RCC_HSE_ON;
    }
    else {
        RCC_OscInitStruct->HSEState = RCC_HSE_OFF;
    }

    /* Get the HSI configuration -----------------------------------------------*/
    if ((RCC->CR & RCC_CR_HSION) == RCC_CR_HSION) {
        RCC_OscInitStruct->HSIState = RCC_HSI_ON;
    }
    else {
        RCC_OscInitStruct->HSIState = RCC_HSI_OFF;
    }

    RCC_OscInitStruct->HSICalibrationValue = (uint32_t)((RCC->CR & RCC_CR_HSITRIM) >> RCC_CR_HSITRIM_Pos);

    /* Get the LSE configuration -----------------------------------------------*/
    if ((RCC->BDCR & RCC_BDCR_LSEBYP) == RCC_BDCR_LSEBYP) {
        RCC_OscInitStruct->LSEState = RCC_LSE_BYPASS;
    }
    else if ((RCC->BDCR & RCC_BDCR_LSEON) == RCC_BDCR_LSEON) {
        RCC_OscInitStruct->LSEState = RCC_LSE_ON;
    }
    else {
        RCC_OscInitStruct->LSEState = RCC_LSE_OFF;
    }

    /* Get the LSI configuration -----------------------------------------------*/
    if ((RCC->CSR & RCC_CSR_LSION) == RCC_CSR_LSION) {
        RCC_OscInitStruct->LSIState = RCC_LSI_ON;
    }
    else {
        RCC_OscInitStruct->LSIState = RCC_LSI_OFF;
    }

    /* Get the PLL configuration -----------------------------------------------*/
    if ((RCC->CR & RCC_CR_PLLON) == RCC_CR_PLLON) {
        RCC_OscInitStruct->PLL.PLLState = RCC_PLL_ON;
    }
    else {
        RCC_OscInitStruct->PLL.PLLState = RCC_PLL_OFF;
    }
    RCC_OscInitStruct->PLL.PLLSource = (uint32_t)(RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC);
    RCC_OscInitStruct->PLL.PLLM = (uint32_t)(RCC->PLLCFGR & RCC_PLLCFGR_PLLM);
    RCC_OscInitStruct->PLL.PLLN = (uint32_t)((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos);
    RCC_OscInitStruct->PLL.PLLP =
        (uint32_t)((((RCC->PLLCFGR & RCC_PLLCFGR_PLLP) + RCC_PLLCFGR_PLLP_0) << 1U) >> RCC_PLLCFGR_PLLP_Pos);
    RCC_OscInitStruct->PLL.PLLQ = (uint32_t)((RCC->PLLCFGR & RCC_PLLCFGR_PLLQ) >> RCC_PLLCFGR_PLLQ_Pos);
    RCC_OscInitStruct->PLL.PLLR = (uint32_t)((RCC->PLLCFGR & RCC_PLLCFGR_PLLR) >> RCC_PLLCFGR_PLLR_Pos);
}
#    endif /* STM32F410xx || STM32F446xx || STM32F469xx || STM32F479xx || STM32F412Zx || STM32F412Vx || STM32F412Rx || \
              STM32F412Cx || STM32F413xx || STM32F423xx */

#endif /* HAL_RCC_MODULE_ENABLED */
/**
 * @}
 */

/**
 * @}
 */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
